├── .gitattributes ├── src ├── fonts │ ├── OpenSans-Regular_6.h │ ├── OpenSans-Regular_7.h │ ├── OpenSans-Regular_14.h │ ├── OpenSans-Regular_15.h │ ├── OpenSans-Regular_24.h │ ├── OpenSans-Regular_26.h │ ├── OpenSans-Regular_33.h │ ├── OpenSans-Regular_37.h │ ├── fonts.h │ ├── README.md │ ├── logos.h │ └── LICENSE.txt ├── truststore │ ├── x509_crt_bundle │ └── README.md ├── sd-partition-table.csv ├── utils │ ├── file.h │ ├── https.h │ ├── file.cpp │ ├── button.h │ ├── obsutils.h │ ├── median.h │ ├── alpdata.h │ ├── timeutils.h │ ├── streams.h │ ├── button.cpp │ ├── multipart.h │ ├── streams.cpp │ ├── obsutils.cpp │ ├── multipart.cpp │ ├── https.cpp │ ├── timeutils.cpp │ └── alpdata.cpp ├── OpenBikeSensorFirmware.h ├── Firmware.h ├── uploader.h ├── bluetooth │ ├── BatteryService.cpp │ ├── DeviceInfoService.cpp │ ├── HeartRateService.h │ ├── DeviceInfoService.h │ ├── BatteryService.h │ ├── HeartRateService.cpp │ ├── ObsService.h │ ├── _IBluetoothService.h │ ├── BluetoothManager.h │ ├── ObsService.cpp │ └── BluetoothManager.cpp ├── configServer.h ├── globals.h ├── VoltageMeter.h ├── variant.h ├── writer.h ├── gpsrecord.h ├── gpsrecord.cpp ├── VoltageMeter.cpp ├── uploader.cpp ├── sensor.h ├── obsimprov.h ├── config.h ├── Firmware.cpp ├── logo.h └── displays.cpp ├── .github ├── dependabot.yml ├── fake-cc ├── README-release.md └── workflows │ └── codeql-analysis.yml ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── vcs.xml ├── copyright │ ├── profiles_settings.xml │ └── openbikesensor_lgpl.xml ├── OpenBikeSensorFirmware.iml ├── runConfigurations │ ├── PlatformIO_Only_Upload.xml │ ├── PlatformIO_Build___Upload.xml │ ├── PlatformIO_Debug.xml │ └── Z_DUMMY_TARGET.xml └── misc.xml ├── .editorconfig ├── open-bike-sensor.code-workspace ├── .gitignore ├── docs └── software │ └── firmware │ ├── initial_flash.md │ ├── obs_cfg.md │ ├── bluetooth_services.md │ └── csv_format.md ├── custom_config.ini.example ├── platformio.ini └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.h text eol=lf 3 | *.cpp text eol=lf 4 | *.ino text eol=lf 5 | -------------------------------------------------------------------------------- /src/fonts/OpenSans-Regular_6.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/fonts/OpenSans-Regular_6.h -------------------------------------------------------------------------------- /src/fonts/OpenSans-Regular_7.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/fonts/OpenSans-Regular_7.h -------------------------------------------------------------------------------- /src/truststore/x509_crt_bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/truststore/x509_crt_bundle -------------------------------------------------------------------------------- /src/fonts/OpenSans-Regular_14.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/fonts/OpenSans-Regular_14.h -------------------------------------------------------------------------------- /src/fonts/OpenSans-Regular_15.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/fonts/OpenSans-Regular_15.h -------------------------------------------------------------------------------- /src/fonts/OpenSans-Regular_24.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/fonts/OpenSans-Regular_24.h -------------------------------------------------------------------------------- /src/fonts/OpenSans-Regular_26.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/fonts/OpenSans-Regular_26.h -------------------------------------------------------------------------------- /src/fonts/OpenSans-Regular_33.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/fonts/OpenSans-Regular_33.h -------------------------------------------------------------------------------- /src/fonts/OpenSans-Regular_37.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbikesensor/OpenBikeSensorFirmware/HEAD/src/fonts/OpenSans-Regular_37.h -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.github/fake-cc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /github/home/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-g++ \ 4 | "$@" 2>&1 \ 5 | | sed 's|: xtensa-esp32-elf|: le32-unknown-nacl|g' \ 6 | | sed 's|=xtensa-esp32-elf|=le32-unknown-nacl|g' 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.{h,cpp,ino}] 10 | charset = utf-8 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/OpenBikeSensorFirmware.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/truststore/README.md: -------------------------------------------------------------------------------- 1 | # Full TLS Truststore 2 | 3 | ## Generate / Update 4 | 5 | 1. curl --remote-name https://raw.githubusercontent.com/espressif/arduino-esp32/master/tools/gen_crt_bundle.py 6 | 1. curl --remote-name https://curl.se/ca/cacert.pem 7 | 1. python3 gen_crt_bundle.py --input cacert.pem 8 | -------------------------------------------------------------------------------- /src/fonts/fonts.h: -------------------------------------------------------------------------------- 1 | #ifndef FONTS_H_ 2 | #define FONTS_H_ 3 | 4 | #include 5 | 6 | #include "OpenSans-Regular_6.h" 7 | #include "OpenSans-Regular_7.h" 8 | #include "OpenSans-Regular_14.h" 9 | #include "OpenSans-Regular_24.h" 10 | #include "OpenSans-Regular_33.h" 11 | 12 | #endif // FONTS_H_ 13 | -------------------------------------------------------------------------------- /open-bike-sensor.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "files.associations": { 9 | "*.tpp": "cpp", 10 | "random": "cpp", 11 | "functional": "cpp", 12 | "cstdint": "cpp" 13 | } 14 | }, 15 | "extensions": { 16 | "recommendations": [ 17 | "platformio.platformio-ide", 18 | "editorconfig.editorconfig" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/fonts/README.md: -------------------------------------------------------------------------------- 1 | # Fonts 2 | 3 | The `OpenSans-Regular_*` files in this directory were generated from 4 | [`OpenSans-Regular.ttf`](https://fonts.google.com/specimen/Open+Sans) using the following bash statement: 5 | 6 | ``` bash 7 | for i in 6 7 14 24 35; do 8 | otf2bdf OpenSans-Regular.ttf -p $i > OpenSans-Regular_$i.bdf 9 | u8g2/tools/font/bdfconv/bdfconv -f 1 -n OpenSans_Regular_$i -o OpenSans-Regular_$i.h OpenSans-Regular_$i.bdf 10 | done 11 | ``` 12 | -------------------------------------------------------------------------------- /src/sd-partition-table.csv: -------------------------------------------------------------------------------- 1 | # Using https://github.com/espressif/arduino-esp32/blob/master/tools/partitions/min_spiffs.csv 2 | # but with minimum ota_1 part size to get larger ota_0 3 | # Name, Type, SubType, Offset, Size, Flags 4 | nvs, data, nvs, 0x009000, 0x005000, 5 | otadata, data, ota, 0x00e000, 0x002000, 6 | app, app, ota_0, 0x010000, 0x380000, 7 | flashApp, app, ota_1, 0x390000, 0x040000, 8 | spiffs, data, spiffs, 0x3D0000, 0x030000, -------------------------------------------------------------------------------- /.idea/runConfigurations/PlatformIO_Only_Upload.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.idea/runConfigurations/PlatformIO_Build___Upload.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.idea/runConfigurations/PlatformIO_Debug.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/runConfigurations/Z_DUMMY_TARGET.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/serialmonitor_settings.xml 2 | .idea/deployment.xml 3 | .idea/modules.xml 4 | .idea/compilerexplorer.settings.xml 5 | *esp32.bin 6 | .pio 7 | .vscode/.browse.c_cpp.db* 8 | .vscode/c_cpp_properties.json 9 | .vscode/launch.json 10 | .vscode/ipch 11 | .vscode/extensions.json 12 | .idea/sonarIssues.xml 13 | CMakeLists.txt 14 | CMakeListsPrivate.txt 15 | cmake-build-*/ 16 | custom_config.ini 17 | !custom_config.ini.example 18 | 19 | # jekyll 20 | docs/_site 21 | docs/.sass-cache 22 | docs/.jekyll-cache 23 | docs/.jekyll-metadata 24 | docs/vendor 25 | 26 | .DS_Store 27 | .vscode 28 | 29 | # for people installing pio venv style 30 | venv 31 | 32 | # jetbrains 33 | .idea -------------------------------------------------------------------------------- /docs/software/firmware/initial_flash.md: -------------------------------------------------------------------------------- 1 | # Initial ESP installation 2 | 3 | There are various ways to flash the ESP, if you are an expert feel 4 | free to choose whatever way you want. The official way to install 5 | the firmware via a browser. To do this open 6 | https://install.openbikesensor.org/ with either your Chrome or Edge browser 7 | and follow up from there. 8 | 9 | For a more none technical description of the process switch to 10 | https://www.openbikesensor.org/docs/firmware/. 11 | 12 | ## History 13 | 14 | You can see the old documentation with different variants in the former 15 | [documentation on github](https://github.com/openbikesensor/OpenBikeSensorFirmware/blob/v0.10.676/docs/software/firmware/initial_flash.md). 16 | -------------------------------------------------------------------------------- /.github/README-release.md: -------------------------------------------------------------------------------- 1 | ## Release Build 2 | 3 | The github action creates a draft release for every build on the 4 | main branch. You can publish any release from the main branch 5 | as either "Pre-release" or final release upon publishing. 6 | 7 | Idea is to delete intermediate releases after a while manually. 8 | 9 | Version number major part is defined in 10 | `src/OpenBikeSensorFirmware.cpp` as OBSVersion. 11 | Just modify the static numeric part, the build script will take 12 | care for the rest. 13 | 14 | Format of the version follows https://semver.org the 3 segment 15 | is automatically increased with every build by github or for 16 | local builds is `-dev`. Also builds from a other branch than 17 | main get `-RC` as part of the version number. 18 | 19 | A typical main branch version looks like `v1.2.432` a build from 20 | any temporary branch is `v1.2-RC433`. Please also note that the numeric 21 | last part (patch) of github builds always increases and is never the 22 | same for 2 different builds. 23 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | -------------------------------------------------------------------------------- /custom_config.ini.example: -------------------------------------------------------------------------------- 1 | ; This file should contain your local modifications to the PlatformIO.ini file. 2 | 3 | [env:myObs] 4 | build_flags = 5 | ${env.build_flags} 6 | ; you can specify a custom config json (see docs/software/firmware/obs_cfg.md) 7 | ; here which will be used for fresh installs based on this firmware 8 | -DCUSTOM_OBS_DEFAULT_CONFIG='"{ obs: [ { displayConfig: 15, offset: [ 30, 30 ], httpPin: \\"12345678\\", wifiSsid: \\"SID\\", wifiPassword: \\"87654321\\" } ] }"' 9 | ; aditional logoutput from 0 (node) over 3 (default info) to 5 debug 10 | -DCORE_DEBUG_LEVEL=3 11 | ; build with development option 12 | ; warning this causes the configuration including the wifi credentials to be sent to serial 13 | -DDEVELOP 14 | ; http lib loglevel 15 | -DHTTPS_LOGLEVEL=3 16 | ; select OBS Variant 17 | -DOBSCLASSIC 18 | ; -DOBSPRO 19 | 20 | 21 | ; === upload_port === 22 | ; Optional. If not set, PlatformIO will try to autodetect the port. 23 | ; -- macOS -- 24 | ; upload_port = /dev/cu.SLAB_USBtoUART 25 | ; -- Windows -- 26 | ; upload_port = COM3 27 | ; === build_flags === 28 | ; build with development option 29 | -------------------------------------------------------------------------------- /.idea/copyright/openbikesensor_lgpl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /src/utils/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_FILE_H 25 | #define OPENBIKESENSORFIRMWARE_FILE_H 26 | 27 | #include 28 | 29 | class FileUtil { 30 | public: 31 | static bool appendFile(fs::FS &fs, const char * path, const char * message); 32 | }; 33 | 34 | #endif //OPENBIKESENSORFIRMWARE_FILE_H 35 | -------------------------------------------------------------------------------- /src/utils/https.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_HTTPS_H 25 | #define OPENBIKESENSORFIRMWARE_HTTPS_H 26 | 27 | #include 28 | #include 29 | 30 | class Https { 31 | public: 32 | static httpsserver::SSLCert * getCertificate(const std::function& progress = nullptr); 33 | static bool removeCertificate(); 34 | static bool existsCertificate(); 35 | }; 36 | 37 | #endif //OPENBIKESENSORFIRMWARE_HTTPS_H 38 | -------------------------------------------------------------------------------- /src/utils/file.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "file.h" 25 | 26 | bool FileUtil::appendFile(fs::FS &fs, const char * path, const char * message) { 27 | bool result = false; 28 | log_i("Appending to file: %s", path); 29 | 30 | File file = fs.open(path, FILE_APPEND); 31 | if (!file) { 32 | log_e("Failed to open file for appending"); 33 | return false; 34 | } 35 | if (file.print(message)) { 36 | result = true; 37 | } else { 38 | log_e("Append failed"); 39 | } 40 | file.close(); 41 | return result; 42 | } 43 | -------------------------------------------------------------------------------- /src/OpenBikeSensorFirmware.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_OPENBIKESENSORFIRMWARE_H 25 | #define OBS_OPENBIKESENSORFIRMWARE_H 26 | 27 | #include 28 | #define CIRCULAR_BUFFER_INT_SAFE 29 | #include 30 | 31 | #include "config.h" 32 | #include "configServer.h" 33 | #include "displays.h" 34 | #include "globals.h" 35 | #include "gps.h" 36 | #include "sensor.h" 37 | #include "pgaSensor.h" 38 | #include "writer.h" 39 | 40 | #include 41 | #include 42 | 43 | #include "bluetooth/BluetoothManager.h" 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/Firmware.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | #ifndef OPENBIKESENSORFIRMWARE_FIRMWARE_H 24 | #define OPENBIKESENSORFIRMWARE_FIRMWARE_H 25 | 26 | 27 | #include 28 | 29 | class Firmware { 30 | public: 31 | explicit Firmware(String userAgent) : mUserAgent(userAgent) {}; 32 | void downloadToSd(String url, String filename, bool unsafe); 33 | bool downloadToFlash(String url, std::function progress, bool unsafe); 34 | String getLastMessage(); 35 | 36 | static String getFlashAppVersion(); 37 | static String checkSdFirmware(); 38 | static bool switchToFlashApp(); 39 | 40 | private: 41 | String mLastMessage; 42 | String mUserAgent; 43 | static const esp_partition_t *findEspFlashAppPartition(); 44 | }; 45 | 46 | 47 | #endif //OPENBIKESENSORFIRMWARE_FIRMWARE_H 48 | -------------------------------------------------------------------------------- /src/uploader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef UPLOADER_H 25 | #define UPLOADER_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | class Uploader { 32 | public: 33 | Uploader(String portalUrl, String userToken); 34 | /* uploads the named file to the portal, 35 | * moves it to uploaded directory and 36 | * returns true if successful, otherwise false */ 37 | bool upload(const String& fileName); 38 | String getLastStatusMessage() const; 39 | String getLastLocation() const; 40 | 41 | private: 42 | const String mPortalUrl; 43 | const String mPortalUserToken; 44 | WiFiClientSecure mWiFiClient; 45 | String mLastLocation = ""; 46 | String mLastStatusMessage = "NO UPLOAD"; 47 | 48 | bool uploadFile(fs::File &file); 49 | }; 50 | #endif 51 | -------------------------------------------------------------------------------- /src/utils/button.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_BUTTON_H 25 | #define OPENBIKESENSORFIRMWARE_BUTTON_H 26 | 27 | 28 | class Button { 29 | public: 30 | explicit Button(int pin); 31 | void handle(); 32 | void handle(unsigned long millis); 33 | int read() const; 34 | int getState() const; 35 | bool gotPressed(); 36 | unsigned long getCurrentStateMillis() const; 37 | unsigned long getPreviousStateMillis() const; 38 | 39 | private: 40 | static const int DEBOUNCE_DELAY_MS = 50; 41 | const int mPin; 42 | unsigned long mLastRawReadMillis; 43 | int mLastRawState; 44 | int mLastState; 45 | unsigned long mLastStateChangeMillis; 46 | unsigned long mPreviousStateDurationMillis = 0; 47 | int mReleaseEvents = 0; 48 | }; 49 | 50 | 51 | #endif //OPENBIKESENSORFIRMWARE_BUTTON_H 52 | -------------------------------------------------------------------------------- /src/bluetooth/BatteryService.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "BatteryService.h" 25 | 26 | const BLEUUID BatteryService::BATTERY_SERVICE_UUID = BLEUUID((uint16_t)0x180f); 27 | const BLEUUID BatteryService::BATTERY_LEVEL_CHARACTERISTIC_UUID = BLEUUID((uint16_t)0x2a19); 28 | 29 | 30 | void BatteryService::setup(BLEServer *pServer) { 31 | mService = pServer->createService(BATTERY_SERVICE_UUID); 32 | 33 | mService->addCharacteristic(&mBatteryLevelCharacteristic); 34 | mBatteryLevelCharacteristic.setCallbacks(&mBatteryLevelCallback); 35 | } 36 | 37 | bool BatteryService::shouldAdvertise() { 38 | return false; 39 | } 40 | 41 | BLEService* BatteryService::getService() { 42 | return mService; 43 | } 44 | 45 | void BatteryLevelCallback::onRead(BLECharacteristic *pCharacteristic) { 46 | *mValue = mGetLevel(); 47 | pCharacteristic->setValue(mValue, 1); 48 | } -------------------------------------------------------------------------------- /src/bluetooth/DeviceInfoService.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "DeviceInfoService.h" 25 | 26 | const BLEUUID DeviceInfoService::SERVICE_UUID = BLEUUID((uint16_t)0x180a); 27 | const BLEUUID DeviceInfoService::FIRMWARE_VERSION_CHARACTERISTIC_UUID = BLEUUID((uint16_t)0x2a26); 28 | const BLEUUID DeviceInfoService::MANUFACTURER_NAME_CHARACTERISTIC_UUID = BLEUUID((uint16_t)0x2a29); 29 | 30 | 31 | void DeviceInfoService::setup(BLEServer *pServer) { 32 | mService = pServer->createService(SERVICE_UUID); 33 | mService->addCharacteristic(&mFirmwareRevisionCharacteristic); 34 | mFirmwareRevisionCharacteristic.setValue(OBSVersion); 35 | mService->addCharacteristic(&mManufacturerNameCharacteristic); 36 | mManufacturerNameCharacteristic.setValue(std::string("openbikesensor.org")); 37 | } 38 | 39 | bool DeviceInfoService::shouldAdvertise() { 40 | return false; 41 | } 42 | 43 | BLEService* DeviceInfoService::getService() { 44 | return mService; 45 | } 46 | -------------------------------------------------------------------------------- /src/bluetooth/HeartRateService.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_BLUETOOTH_HEARTRATESERVICE_H 25 | #define OBS_BLUETOOTH_HEARTRATESERVICE_H 26 | 27 | #include "_IBluetoothService.h" 28 | 29 | class HeartRateService : public IBluetoothService { 30 | public: 31 | void setup(BLEServer *pServer) override; 32 | bool shouldAdvertise() override; 33 | BLEService* getService() override; 34 | void newSensorValues(uint32_t millis, uint16_t leftValue, uint16_t rightValue) override; 35 | 36 | private: 37 | BLEService *mService = nullptr; 38 | BLECharacteristic mHeartRateMeasurementCharacteristics 39 | = BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_HEART_RATE_MEAS), BLECharacteristic::PROPERTY_NOTIFY); 40 | BLE2902 mHeartRateMeasurementConfiguration; 41 | unsigned long mCollectionStartTime = 0; 42 | uint16_t mMinimumDistance = MAX_SENSOR_VALUE; 43 | uint8_t mValue[4]; 44 | 45 | static const BLEUUID SERVICE_UUID; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/fonts/logos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | const unsigned char BatterieLogo1 [] PROGMEM = { 25 | 0x1C, 0x3E, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3E 26 | }; 27 | const unsigned char BatterieLogo2 [] PROGMEM = { 28 | 0x1C, 0x3E, 0x41, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3E 29 | }; 30 | const unsigned char BatterieLogo3 [] PROGMEM = { 31 | 0x1C, 0x3E, 0x41, 0x41, 0x7F, 0x7F, 0x7F, 0x7F, 0x3E 32 | }; 33 | const unsigned char BatterieLogo4 [] PROGMEM = { 34 | 0x1C, 0x3E, 0x41, 0x41, 0x41, 0x7F, 0x7F, 0x7F, 0x3E 35 | }; 36 | const unsigned char BatterieLogo5 [] PROGMEM = { 37 | 0x1C, 0x3E, 0x41, 0x41, 0x41, 0x41, 0x7F, 0x7F, 0x3E 38 | }; 39 | const unsigned char BatterieLogo6 [] PROGMEM = { 40 | 0x1C, 0x3E, 0x41, 0x41, 0x41, 0x41, 0x41, 0x7F, 0x3E 41 | }; 42 | const unsigned char BatterieLogo7 [] PROGMEM = { 43 | 0x1C, 0x3E, 0x41, 0x41, 0x7F, 0x7F, 0x7F, 0x7F, 0x3E 44 | }; 45 | 46 | const unsigned char TempLogo [] PROGMEM = { 47 | 0x10, 0x28, 0x28, 0x28, 0x28, 0x28, 0x44, 0x44, 0x38 48 | }; 49 | -------------------------------------------------------------------------------- /src/configServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | // Based on https://lastminuteengineers.com/esp32-ota-web-updater-arduino-ide/ 25 | // The information provided on the LastMinuteEngineers.com may be used, copied, 26 | // remix, transform, build upon the material and distributed for any purposes 27 | // only if provided appropriate credit to the author and link to the original article. 28 | 29 | #ifndef OBS_CONFIG_SERVER_H 30 | #define OBS_CONFIG_SERVER_H 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "config.h" 41 | #include "globals.h" 42 | #include "gps.h" 43 | 44 | // DNS server 45 | //const byte DNS_PORT = 53; 46 | //DNSServer dnsServer; 47 | 48 | void startServer(ObsConfig *pConfig); 49 | bool configServerWasConnectedViaHttp(); 50 | void uploadTracks(httpsserver::HTTPResponse *res = nullptr); 51 | void configServerHandle(); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/utils/obsutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_OBSUTILS_H 25 | #define OPENBIKESENSORFIRMWARE_OBSUTILS_H 26 | 27 | #include 28 | 29 | /** 30 | * Class for internal - static only methods. 31 | */ 32 | class ObsUtils { 33 | public: 34 | static String createTrackUuid(); 35 | static String sha256ToString(byte *sha256); 36 | /* Strips technical details like extension or '/' from the file name. */ 37 | static String stripCsvFileName(const String &fileName); 38 | static String encodeForXmlAttribute(const String & text); 39 | static String encodeForXmlText(const String &text); 40 | static String encodeForCsvField(const String &field); 41 | static String encodeForUrl(const String &url); 42 | static String toScaledByteString(uint64_t size); 43 | static void logHexDump(const uint8_t *buffer, uint16_t length); 44 | static String to3DigitString(uint32_t value); 45 | 46 | }; 47 | 48 | 49 | #endif //OPENBIKESENSORFIRMWARE_OBSUTILS_H 50 | -------------------------------------------------------------------------------- /src/bluetooth/DeviceInfoService.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_BLUETOOTH_DEVICEINFOSERVICE_H 25 | #define OBS_BLUETOOTH_DEVICEINFOSERVICE_H 26 | 27 | #include "_IBluetoothService.h" 28 | 29 | /* 30 | * See https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=244369 for spec 31 | */ 32 | class DeviceInfoService : public IBluetoothService { 33 | public: 34 | void setup(BLEServer *pServer) override; 35 | bool shouldAdvertise() override; 36 | BLEService* getService() override; 37 | 38 | private: 39 | BLEService *mService = nullptr; 40 | BLECharacteristic mFirmwareRevisionCharacteristic 41 | = BLECharacteristic(FIRMWARE_VERSION_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ); 42 | BLECharacteristic mManufacturerNameCharacteristic 43 | = BLECharacteristic(MANUFACTURER_NAME_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ); 44 | 45 | static const BLEUUID SERVICE_UUID; 46 | static const BLEUUID FIRMWARE_VERSION_CHARACTERISTIC_UUID; 47 | static const BLEUUID MANUFACTURER_NAME_CHARACTERISTIC_UUID; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '37 23 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | container: 28 | # could use a container with sq tools already installed 29 | image: infinitecoding/platformio-for-ci:latest 30 | 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | language: [ 'cpp' ] 35 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 36 | # Learn more: 37 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v4 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | - name: Build firmware 54 | run: | 55 | platformio ci --build-dir="./bin" --keep-build-dir --project-conf=platformio.ini ./src/ 56 | 57 | - name: Perform CodeQL Analysis 58 | uses: github/codeql-action/analyze@v3 59 | -------------------------------------------------------------------------------- /src/globals.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_GLOBALS_H 25 | #define OBS_GLOBALS_H 26 | 27 | #include 28 | 29 | // Forward declare classes to build (because there is a cyclic dependency between sensor.h and displays.h) 30 | class DisplayDevice; 31 | class HCSR04SensorManager; 32 | 33 | 34 | #include "utils/obsutils.h" 35 | #include "config.h" 36 | #include "displays.h" 37 | #include "sensor.h" 38 | #include "pgaSensor.h" 39 | #include "VoltageMeter.h" 40 | #include "utils/button.h" 41 | #include "variant.h" 42 | 43 | // This file should contain declarations of all variables that will be used globally. 44 | // The variables don't have to be set here, but need to be declared. 45 | 46 | // Version 47 | extern const char *OBSVersion; 48 | 49 | // PINs 50 | extern const int PUSHBUTTON_PIN; 51 | 52 | extern int confirmedMeasurements; 53 | extern int numButtonReleased; 54 | 55 | extern Config config; 56 | 57 | 58 | extern DisplayDevice* obsDisplay; 59 | 60 | #ifdef OBSPRO 61 | extern PGASensorManager *sensorManager; 62 | #endif 63 | #ifdef OBSCLASSIC 64 | extern HCSR04SensorManager* sensorManager; 65 | #endif 66 | 67 | extern VoltageMeter* voltageMeter; 68 | 69 | extern Button button; 70 | 71 | class Gps; 72 | extern Gps gps; 73 | 74 | extern const uint8_t LEFT_SENSOR_ID; 75 | extern const uint8_t RIGHT_SENSOR_ID; 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/utils/median.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_MEDIAN_H 25 | #define OPENBIKESENSORFIRMWARE_MEDIAN_H 26 | 27 | #include 28 | 29 | template class Median { 30 | 31 | public: 32 | /* Simple implementation, size must be odd! */ 33 | Median(size_t size, T initialValue): 34 | size{size}, 35 | mid{size/2}, 36 | data{new T[size]}, 37 | temp{new T[size]}, 38 | pos{0} { 39 | for(size_t i = 0; i < size; i++) { 40 | data[i] = initialValue; 41 | } 42 | }; 43 | ~Median() { 44 | log_i("Will free Median(%d/%d) -> 0x%lx", size, mid, data); 45 | delete[] data; 46 | delete[] temp; 47 | }; 48 | void addValue(T value) { 49 | sorted = false; 50 | data[pos++] = value; 51 | if (pos >= size) { 52 | pos = 0; 53 | } 54 | }; 55 | T median() { 56 | if (!sorted) { 57 | memcpy(temp, data, sizeof(T) * size); // std:copy needs to much mem 58 | std::sort(&temp[0], &temp[size]); 59 | sorted = true; 60 | } 61 | return temp[mid]; 62 | }; 63 | 64 | private: 65 | const size_t size; 66 | const size_t mid; 67 | T *data; 68 | T *temp; 69 | size_t pos = 0; 70 | boolean sorted = false; 71 | }; 72 | 73 | #endif //OPENBIKESENSORFIRMWARE_MEDIAN_H 74 | -------------------------------------------------------------------------------- /src/utils/alpdata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_ALPDATA_H 25 | #define OPENBIKESENSORFIRMWARE_ALPDATA_H 26 | 27 | #include 28 | #include "displays.h" 29 | 30 | static const char *const LAST_MODIFIED_HEADER_FILE_NAME = "/current_14d.hdr"; 31 | 32 | static const char *const ALP_DATA_FILE_NAME = "/current_14d.alp"; 33 | static const char *const ALP_NEW_DATA_FILE_NAME = "/current_14d.new"; 34 | static const char *const AID_INI_DATA_FILE_NAME = "/aid_ini.ubx"; 35 | 36 | static const int32_t ALP_DATA_MIN_FILE_SIZE = 60000; // We have seen 71k ALP files - so lets hope 60k is safe 37 | 38 | static const char *const ALP_DOWNLOAD_URL = "https://alp.u-blox.com/current_14d.alp"; 39 | 40 | class AlpData { 41 | public: 42 | static void update(DisplayDevice *display); 43 | static bool available(); 44 | static void saveMessage(const uint8_t *data, size_t size); 45 | static size_t loadMessage(uint8_t *data, size_t size); 46 | 47 | uint16_t fill(uint8_t *data, size_t ofs, uint16_t dataSize); 48 | void save(const uint8_t *data, size_t offset, int length); 49 | 50 | private: 51 | static void saveLastModified(const String &header); 52 | static String loadLastModified(); 53 | static void displayHttpClientError(DisplayDevice *display, int httpError); 54 | File mAlpDataFile; 55 | 56 | }; 57 | 58 | 59 | #endif //OPENBIKESENSORFIRMWARE_ALPDATA_H 60 | -------------------------------------------------------------------------------- /src/VoltageMeter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_VOLTAGEMETER_H 25 | #define OPENBIKESENSORFIRMWARE_VOLTAGEMETER_H 26 | 27 | #include 28 | #include 29 | 30 | class VoltageMeter { 31 | public: 32 | explicit VoltageMeter( 33 | uint8_t batteryPin = 34, 34 | adc1_channel_t channel = ADC1_CHANNEL_6); 35 | /* Returns the (smoothed) value in Volts. */ 36 | double read(); 37 | int8_t readPercentage(); 38 | bool hasReadings(); 39 | bool isWarningLevel(); 40 | 41 | private: 42 | /* This one is typically NOT used, our ESP32 dos have 43 | * Vref stored in the eFuse which takes priority. */ 44 | static const uint16_t REF_VOLTAGE_MILLI_VOLT = 1100; 45 | static const int16_t MINIMUM_SAMPLES = 64; 46 | static const int16_t SAMPLES_DIVIDE = 128; 47 | 48 | /* Below this value a warning will be printed during startup. */ 49 | constexpr static const double BATTERY_WARNING_LEVEL = 3.47; 50 | /* Below this value it is assumed there is no voltage reading at all. */ 51 | constexpr static const double BATTERY_NO_READ_LEVEL = 3.00; 52 | 53 | const uint8_t mBatteryPin; 54 | const adc1_channel_t mBatteryAdcChannel; 55 | esp_adc_cal_characteristics_t adc_chars; 56 | int16_t lastSmoothedReading; 57 | int readSmoothed(); 58 | int readRaw() const; 59 | }; 60 | 61 | 62 | #endif //OPENBIKESENSORFIRMWARE_VOLTAGEMETER_H 63 | -------------------------------------------------------------------------------- /src/bluetooth/BatteryService.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_BATTERYSERVICE_H 25 | #define OPENBIKESENSORFIRMWARE_BATTERYSERVICE_H 26 | 27 | #include "_IBluetoothService.h" 28 | #include 29 | 30 | class BatteryLevelCallback : public BLECharacteristicCallbacks { 31 | public: 32 | explicit BatteryLevelCallback(uint8_t *value, std::function getLevel) : 33 | mValue(value), mGetLevel(getLevel) {}; 34 | 35 | void onRead(BLECharacteristic *pCharacteristic) override; 36 | 37 | private: 38 | uint8_t *mValue; 39 | const std::function mGetLevel; 40 | }; 41 | 42 | class BatteryService : public IBluetoothService { 43 | public: 44 | explicit BatteryService(std::function getLevel) : mBatteryLevelCallback(&mBatteryLevelValue, getLevel) { }; 45 | void setup(BLEServer *pServer) override; 46 | bool shouldAdvertise() override; 47 | BLEService* getService() override; 48 | 49 | private: 50 | BLEService *mService = nullptr; 51 | BLECharacteristic mBatteryLevelCharacteristic = BLECharacteristic( 52 | BATTERY_LEVEL_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ); 53 | 54 | uint8_t mBatteryLevelValue = 42; 55 | BatteryLevelCallback mBatteryLevelCallback; 56 | 57 | static const BLEUUID BATTERY_SERVICE_UUID; 58 | static const BLEUUID BATTERY_LEVEL_CHARACTERISTIC_UUID; 59 | }; 60 | 61 | 62 | #endif //OPENBIKESENSORFIRMWARE_BATTERYSERVICE_H 63 | -------------------------------------------------------------------------------- /src/utils/timeutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_TIMEUTILS_H 25 | #define OPENBIKESENSORFIRMWARE_TIMEUTILS_H 26 | 27 | #include 28 | 29 | class TimeUtils { 30 | public: 31 | static const time_t PAST_TIME; 32 | static String dateTimeToString(time_t timeIn = 0); 33 | static String timeToString(time_t theTime =0); 34 | static String dateTimeToHttpHeaderString(time_t theTime); 35 | static void setClockByNtp(const char *ntpServer = nullptr); 36 | static void setClockByNtpAndWait(const char *ntpServer = nullptr, uint32_t timeout = 3 * 60 * 1000); 37 | static void setClockByGps(uint32_t iTow, int32_t fTow, int16_t week, int8_t leapS = 0); 38 | static bool systemTimeIsSet(); 39 | static int16_t getLeapSecondsGps(time_t gps); 40 | static int16_t getLeapSecondsUtc(time_t gps); 41 | static time_t gpsDayToTime(uint16_t week, uint16_t dayOfWeek); 42 | static time_t toTime(uint16_t week, uint32_t weekTime); 43 | static uint32_t utcTimeToTimeOfWeek(time_t t); 44 | static uint16_t utcTimeToWeekNumber(time_t t); 45 | 46 | private: 47 | static const char *WEEK_DAYS[7]; 48 | static const char *MONTHS[12]; 49 | static const uint32_t GPS_EPOCH_OFFSET; 50 | static const uint32_t SECONDS_PER_DAY; 51 | static const uint32_t SECONDS_PER_WEEK; 52 | static const char *weekDayToString(uint8_t wDay); 53 | static const char *monthToString(uint8_t mon); 54 | }; 55 | 56 | 57 | #endif //OPENBIKESENSORFIRMWARE_TIMEUTILS_H 58 | -------------------------------------------------------------------------------- /src/utils/streams.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_STREAMS_H 25 | #define OPENBIKESENSORFIRMWARE_STREAMS_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | class StringStream : public Stream { 34 | public: 35 | explicit StringStream(String str); 36 | 37 | int available() override; 38 | 39 | int read() override; 40 | 41 | int peek() override; 42 | 43 | void flush() override; 44 | 45 | size_t write(uint8_t) override; 46 | 47 | size_t readBytes(char *buffer, size_t length) override; 48 | 49 | private: 50 | String string; 51 | size_t pos = 0; 52 | }; 53 | 54 | static StringStream EMPTY_STREAM(""); 55 | 56 | class StreamOfStreams : public Stream { 57 | public: 58 | void push(Stream *addedStream); 59 | 60 | int available() override; 61 | 62 | int read() override; 63 | 64 | int peek() override; 65 | 66 | void flush() override; 67 | 68 | size_t write(uint8_t) override; 69 | 70 | void setProgressListener(std::function); 71 | 72 | size_t readBytes(char *buffer, size_t length) override; 73 | 74 | private: 75 | Stream *current = nullptr; 76 | std::vector streams; 77 | size_t pos = 0; 78 | std::function progressListener = nullptr; 79 | size_t overallBytePos = 0; 80 | 81 | 82 | Stream *getCurrent(); 83 | 84 | Stream *getNext(); 85 | }; 86 | 87 | 88 | #endif //OPENBIKESENSORFIRMWARE_STREAMS_H 89 | -------------------------------------------------------------------------------- /src/utils/button.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "button.h" 25 | #include "esp32-hal-gpio.h" 26 | #include "variant.h" 27 | 28 | Button::Button(int pin) : mPin(pin) { 29 | pinMode(pin, INPUT); 30 | mLastStateChangeMillis = mLastRawReadMillis = millis(); 31 | mLastState = mLastRawState = read(); 32 | } 33 | 34 | void Button::handle() { 35 | handle(millis()); 36 | } 37 | 38 | void Button::handle(unsigned long millis) { 39 | const int state = read(); 40 | 41 | if (state != mLastRawState) { 42 | mLastRawReadMillis = millis; 43 | mLastRawState = state; 44 | } 45 | 46 | if (state != mLastState && millis - mLastRawReadMillis > DEBOUNCE_DELAY_MS) { 47 | mLastState = state; 48 | mPreviousStateDurationMillis = millis - mLastStateChangeMillis; 49 | mLastStateChangeMillis = millis; 50 | if (state == LOW) { 51 | // can distinguish long / short here if needed 52 | mReleaseEvents++; 53 | } 54 | } 55 | } 56 | 57 | bool Button::gotPressed() { 58 | if (mReleaseEvents > 0) { 59 | mReleaseEvents = 0; 60 | return true; 61 | } else { 62 | return false; 63 | } 64 | } 65 | 66 | int Button::read() const { 67 | // not debounced 68 | #ifdef OBSPRO 69 | return !digitalRead(mPin); 70 | #else 71 | return digitalRead(mPin); 72 | #endif 73 | } 74 | 75 | int Button::getState() const { 76 | // debounced, needs handle to be called 77 | return mLastState; 78 | } 79 | 80 | unsigned long Button::getCurrentStateMillis() const { 81 | return millis() - mLastStateChangeMillis; 82 | } 83 | 84 | unsigned long Button::getPreviousStateMillis() const { 85 | return mPreviousStateDurationMillis; 86 | } 87 | -------------------------------------------------------------------------------- /src/bluetooth/HeartRateService.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "HeartRateService.h" 25 | 26 | const unsigned long measurementInterval = 500; 27 | 28 | const BLEUUID HeartRateService::SERVICE_UUID = BLEUUID((uint16_t)ESP_GATT_UUID_HEART_RATE_SVC); 29 | 30 | void HeartRateService::setup(BLEServer *pServer) { 31 | mService = pServer->createService(SERVICE_UUID); // Keep the defaults!!, 5); 32 | mService->addCharacteristic(&mHeartRateMeasurementCharacteristics); 33 | mHeartRateMeasurementCharacteristics.addDescriptor(&mHeartRateMeasurementConfiguration); 34 | mValue[0] = mValue[1] = mValue[2] = 0; 35 | mHeartRateMeasurementCharacteristics.setValue(mValue, 2); 36 | 37 | mCollectionStartTime = millis(); 38 | } 39 | 40 | bool HeartRateService::shouldAdvertise() { 41 | return true; 42 | } 43 | 44 | BLEService* HeartRateService::getService() { 45 | return mService; 46 | } 47 | 48 | void HeartRateService::newSensorValues( 49 | const uint32_t millis, const uint16_t leftValue, const uint16_t rightValue) { 50 | if (leftValue < mMinimumDistance) { 51 | mMinimumDistance = leftValue; 52 | } 53 | if ((millis - mCollectionStartTime) < measurementInterval) { 54 | return; 55 | } 56 | 57 | if (mHeartRateMeasurementConfiguration.getNotifications()) { 58 | mValue[0] = mMinimumDistance <= UINT8_MAX ? 0 : 1; // 8/16 bit data no other flags set; 59 | mValue[1] = mMinimumDistance & 0xFFu; 60 | mValue[2] = mMinimumDistance >> 8u; 61 | mHeartRateMeasurementCharacteristics.setValue(mValue, mMinimumDistance <= UINT8_MAX ? 2 : 3); 62 | mHeartRateMeasurementCharacteristics.notify(); 63 | } 64 | 65 | // Reset values 66 | mMinimumDistance = MAX_SENSOR_VALUE; 67 | mCollectionStartTime = millis; 68 | } 69 | -------------------------------------------------------------------------------- /src/variant.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2023 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef VARIANT_H 25 | #define VARIANT_H 26 | 27 | 28 | // Use custom_config.ini to set the needed variant! 29 | // If set, the firmware is build for the OBSPro hardware variant 30 | // The main differences are: 31 | // - The button is inverted 32 | // - The button is also responsible for soft-power-off 33 | // - The display is a JHD12864-G156BT which is SPI based 34 | // - The ultrasonic sensors are PGA460 based 35 | //#define OBSPRO 36 | 37 | // If set, the firmware is build for the OBSClassic 38 | //#define OBSCLASSIC 39 | 40 | // Settings specific to OBSPro 41 | #ifdef OBSPRO 42 | #define LCD_CS_PIN 12 43 | #define LCD_DC_PIN 27 44 | #define LCD_RESET_PIN 4 45 | 46 | #define SENSOR1_SCK_PIN 25 47 | #define SENSOR1_MOSI_PIN 33 48 | #define SENSOR1_MISO_PIN 32 49 | 50 | #define SENSOR2_SCK_PIN 14 51 | #define SENSOR2_MOSI_PIN 15 52 | #define SENSOR2_MISO_PIN 21 53 | #define UBX_M10 54 | 55 | #define POWER_KEEP_ALIVE_INTERVAL_MS 5000UL 56 | #endif 57 | 58 | // Settings specific to OBSClassic 59 | #if OBSCLASSIC 60 | #define UBX_M6 61 | #endif 62 | 63 | 64 | // General settings 65 | #define NUMBER_OF_TOF_SENSORS 2 66 | #define MAX_SENSOR_VALUE 999 67 | #define MAX_NUMBER_MEASUREMENTS_PER_INTERVAL 30 // is 1000/SENSOR_QUIET_PERIOD_AFTER_START_MICRO_SEC/2 68 | #define MEDIAN_DISTANCE_MEASURES 3 69 | 70 | #define MIN_DISTANCE_MEASURED_CM 2 71 | #ifdef OBSPRO 72 | #define MAX_DISTANCE_MEASURED_CM 600 73 | #else 74 | #define MAX_DISTANCE_MEASURED_CM 320 // candidate to check I could not get good readings above 300 75 | #endif 76 | 77 | #define MICRO_SEC_TO_CM_DIVIDER 58 // sound speed 340M/S, 2 times back and forward 78 | 79 | #define MIN_DURATION_MICRO_SEC (MIN_DISTANCE_MEASURED_CM * MICRO_SEC_TO_CM_DIVIDER) 80 | #define MAX_DURATION_MICRO_SEC (MAX_DISTANCE_MEASURED_CM * MICRO_SEC_TO_CM_DIVIDER) 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/writer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_WRITER_H 25 | #define OBS_WRITER_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "gps.h" 32 | #include "globals.h" 33 | 34 | 35 | struct DataSet { 36 | time_t time; 37 | uint32_t millis; 38 | String comment; 39 | GpsRecord gpsRecord; 40 | double batteryLevel; 41 | std::vector sensorValues; 42 | std::vector confirmedDistances; 43 | std::vector confirmedDistancesIndex; 44 | uint16_t confirmed = 0; 45 | String marked; 46 | bool invalidMeasurement = false; 47 | bool isInsidePrivacyArea = false; 48 | uint8_t factor = MICRO_SEC_TO_CM_DIVIDER; 49 | uint8_t measurements; 50 | 51 | uint16_t position = 0; // fixme: num sensors? 52 | uint16_t startOffsetMilliseconds[MAX_NUMBER_MEASUREMENTS_PER_INTERVAL + 1]; 53 | int32_t readDurationsLeftInMicroseconds[MAX_NUMBER_MEASUREMENTS_PER_INTERVAL + 1]; 54 | int32_t readDurationsRightInMicroseconds[MAX_NUMBER_MEASUREMENTS_PER_INTERVAL + 1]; 55 | }; 56 | 57 | class FileWriter { 58 | public: 59 | FileWriter() = default;; 60 | explicit FileWriter(String ext) : 61 | mFileExtension(std::move(ext)) {}; 62 | virtual ~FileWriter() = default; 63 | void setFileName(); 64 | virtual bool writeHeader(String trackId) = 0; 65 | virtual bool append(DataSet &) = 0; 66 | bool appendString(const String &s); 67 | bool flush(); 68 | unsigned long getWriteTimeMillis() const; 69 | 70 | protected: 71 | uint16_t getBufferLength() const; 72 | 73 | private: 74 | static void storeTrackNumber(int trackNumber); 75 | static int getTrackNumber(); 76 | void correctFilename(); 77 | String mBuffer; 78 | String mFileExtension; 79 | String mFileName; 80 | const unsigned long mStartedMillis = millis(); 81 | bool mFinalFileName = false; 82 | unsigned long mWriteTimeMillis = 0; 83 | 84 | }; 85 | 86 | class CSVFileWriter : public FileWriter { 87 | public: 88 | CSVFileWriter() : FileWriter(EXTENSION) {} 89 | ~CSVFileWriter() override = default; 90 | bool writeHeader(String trackId) override; 91 | bool append(DataSet&) override; 92 | static const String EXTENSION; 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/bluetooth/ObsService.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_OBSSERVICE_H 25 | #define OPENBIKESENSORFIRMWARE_OBSSERVICE_H 26 | 27 | #include "_IBluetoothService.h" 28 | 29 | 30 | class ObsTimeServiceCallback : public BLECharacteristicCallbacks { 31 | public: 32 | void onRead(BLECharacteristic *pCharacteristic) override; 33 | }; 34 | 35 | 36 | class ObsService : public IBluetoothService { 37 | public: 38 | ObsService(uint16_t leftOffset, uint16_t rightOffset, const String &trackId); 39 | void setup(BLEServer *pServer) override; 40 | bool shouldAdvertise() override; 41 | BLEService* getService() override; 42 | void newSensorValues(uint32_t millis, uint16_t leftValue, uint16_t rightValue) override; 43 | void newPassEvent(uint32_t millis, uint16_t leftValue, uint16_t rightValue) override; 44 | 45 | private: 46 | BLEService *mService = nullptr; 47 | 48 | BLECharacteristic mTimeCharacteristic 49 | = BLECharacteristic(OBS_TIME_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ); 50 | ObsTimeServiceCallback mTimeCharacteristicsCallback; 51 | 52 | BLECharacteristic mDistanceCharacteristic 53 | = BLECharacteristic(OBS_DISTANCE_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY); 54 | BLE2902 mDistanceConfiguration; 55 | 56 | BLECharacteristic mButtonCharacteristic 57 | = BLECharacteristic(OBS_BUTTON_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY); 58 | 59 | BLECharacteristic mOffsetCharacteristic 60 | = BLECharacteristic(OBS_OFFSET_CHARACTERISTIC_UUID,BLECharacteristic::PROPERTY_READ); 61 | 62 | BLECharacteristic mTrackIdCharacteristic 63 | = BLECharacteristic(OBS_TRACK_ID_CHARACTERISTIC_UUID,BLECharacteristic::PROPERTY_READ); 64 | 65 | static const BLEUUID OBS_SERVICE_UUID; 66 | static const BLEUUID OBS_TIME_CHARACTERISTIC_UUID; 67 | static const BLEUUID OBS_DISTANCE_CHARACTERISTIC_UUID; 68 | static const BLEUUID OBS_BUTTON_CHARACTERISTIC_UUID; 69 | static const BLEUUID OBS_OFFSET_CHARACTERISTIC_UUID; 70 | static const BLEUUID OBS_TRACK_ID_CHARACTERISTIC_UUID; 71 | static void sendEventData(BLECharacteristic *characteristic, 72 | uint32_t millis, uint16_t leftValue, uint16_t rightValue); 73 | 74 | }; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/bluetooth/_IBluetoothService.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_BLUETOOTH_IBLUETOOTHSERVICE_H 25 | #define OBS_BLUETOOTH_IBLUETOOTHSERVICE_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "globals.h" 33 | 34 | /** 35 | * This class interface defines how a bluetooth service should work. 36 | * Any child class should override every public method. 37 | */ 38 | class IBluetoothService { 39 | public: 40 | /** 41 | * This method initializes the class and expects the instance to create its 42 | * own BLEService and its characteristics. 43 | * @param pServer pointer to the bluetooth server 44 | */ 45 | virtual void setup(BLEServer *pServer) = 0; 46 | 47 | /** 48 | * Whether this bluetooth service should be advertised or not. 49 | */ 50 | virtual bool shouldAdvertise() = 0; 51 | 52 | /** 53 | * Gets the only BLEService that was created in setup(). 54 | */ 55 | virtual BLEService* getService() = 0; 56 | 57 | /** 58 | * Processes new sensor values from both sides. 59 | * @param millis sender millis counter at the time of measurement of the left value 60 | * @param leftValue sensor value of the left side (MAX_SENSOR_VALUE for no reading) 61 | * @param rightValues sensor value of the right side (MAX_SENSOR_VALUE for no reading) 62 | */ 63 | virtual void newSensorValues(uint32_t millis, uint16_t leftValue, uint16_t rightValue) { 64 | // empty default implementation 65 | } 66 | 67 | /** 68 | * Processes new confirmed overtake event. 69 | * @param millis sender millis counter at the time of measurement of the left value 70 | * @param leftValue sensor value of the left side (MAX_SENSOR_VALUE for no reading) 71 | * @param rightValues sensor value of the right side (MAX_SENSOR_VALUE for no reading) 72 | */ 73 | virtual void newPassEvent(uint32_t millis, uint16_t leftValue, uint16_t rightValue) { 74 | // empty default implementation 75 | } 76 | 77 | protected: 78 | static String valueAsString(uint16_t value) { 79 | if (value == MAX_SENSOR_VALUE || value == 0) { 80 | return String(""); 81 | } else{ 82 | return String(value); 83 | } 84 | } 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; Copyright (C) 2019-2021 OpenBikeSensor Contributors 2 | ; Contact: https://openbikesensor.org 3 | ; 4 | ; This file is part of the OpenBikeSensor firmware. 5 | ; 6 | ; The OpenBikeSensor firmware is free software: you can 7 | ; redistribute it and/or modify it under the terms of the GNU 8 | ; Lesser General Public License as published by the Free Software 9 | ; Foundation, either version 3 of the License, or (at your option) 10 | ; any later version. 11 | ; 12 | ; OpenBikeSensor firmware is distributed in the hope that 13 | ; it will be useful, but WITHOUT ANY WARRANTY; without even the 14 | ; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 15 | ; PURPOSE. See the GNU Lesser General Public License for more 16 | ; details. 17 | ; 18 | ; You should have received a copy of the GNU Lesser General Public 19 | ; License along with the OpenBikeSensor firmware. If not, 20 | ; see . 21 | 22 | ; PlatformIO Project Configuration File 23 | ; 24 | ; Build options: build flags, source filter 25 | ; Upload options: custom upload port, speed and extra flags 26 | ; Library options: dependencies, extra library storages 27 | ; Advanced options: extra scripting 28 | ; 29 | ; Please visit documentation for the other options and examples 30 | ; https://docs.platformio.org/page/projectconf.html 31 | 32 | ; If you need to set some configurations differently for your local setup, copy 33 | ; the 'custom_config.ini.example' to 'custom_config.ini' and put your changes there. 34 | ; This new file will be ignored by git and therefore won't be overwritten at some point. 35 | 36 | [platformio] 37 | src_dir = src 38 | extra_configs = custom_config.ini 39 | 40 | [env] 41 | platform = espressif32 @ 6.9.0 42 | board = esp32dev 43 | framework = arduino 44 | monitor_speed = 115200 45 | ; This upload speed is the highest I can get, but I do get reliable uploads 46 | ; with it. If uploads fail for you, comment out the following line: 47 | upload_speed = 921600 48 | board_build.partitions = src/sd-partition-table.csv 49 | board_build.embed_txtfiles = src/truststore/x509_crt_bundle 50 | lib_deps = 51 | adafruit/Adafruit BusIO @ ^1.13.1 52 | ; https://arduinojson.org/v6/api/ 53 | bblanchon/ArduinoJson @ ^6.21.5 54 | rlogiacco/CircularBuffer @ ^1.4.0 55 | ; olikraus/U8g2 @ ^2.35.9 56 | https://codeberg.org/j000bs/U8g2_Arduino.git#jhd-fix 57 | ; replaced by U8g2 thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays @ ^4.5.0 58 | adafruit/Adafruit BMP280 Library@^2.6.8 59 | pololu/VL53L0X@^1.3.1 60 | ; https://github.com/fhessel/esp32_https_server 61 | https://github.com/amandel/esp32_https_server.git#hotfix/openbikesensor 62 | ; TODO: https://github.com/jasenk2/esp32_https_server.git#esp_tls 63 | ; esp32_https_server@ 64 | build_flags = 65 | -DCORE_DEBUG_LEVEL=3 66 | -DHTTPS_LOGLEVEL=3 67 | -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=1024 68 | ; reduce probability of https://github.com/fhessel/esp32_https_server/pull/123 69 | -DHTTPS_CONNECTION_DATA_CHUNK_SIZE=1024 70 | ; build number "-dev" will be replaced in github action 71 | -DBUILD_NUMBER=\"-dev\" 72 | 73 | [env:obs] 74 | build_flags = 75 | ${env.build_flags} 76 | -DOBSCLASSIC 77 | 78 | [env:obspro] 79 | build_flags = 80 | ${env.build_flags} 81 | -DOBSPRO 82 | -------------------------------------------------------------------------------- /src/utils/multipart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_MULTIPART_H 25 | #define OPENBIKESENSORFIRMWARE_MULTIPART_H 26 | 27 | #include 28 | #include 29 | #include "streams.h" 30 | 31 | class MultipartData { 32 | public: 33 | virtual String getHeaders() = 0; 34 | 35 | virtual Stream *asStream() = 0; 36 | 37 | virtual size_t length() = 0; 38 | 39 | explicit MultipartData(String name, String contentType = ""); 40 | 41 | protected: 42 | String getBaseHeaders(const String& fileName = ""); 43 | 44 | String name; 45 | String contentType; 46 | }; 47 | 48 | class MultipartDataString : public MultipartData { 49 | public: 50 | 51 | MultipartDataString(String name, const String& content, String contentType = ""); 52 | 53 | String getHeaders() override; 54 | 55 | Stream *asStream() override; 56 | 57 | size_t length() override; 58 | 59 | private: 60 | String content; 61 | StringStream contentStream; 62 | }; 63 | 64 | class MultipartDataStream : public MultipartData { 65 | public: 66 | String getHeaders() override; 67 | 68 | Stream *asStream() override; 69 | 70 | size_t length() override; 71 | 72 | MultipartDataStream(String name, String fileName, File *content, String contentType = ""); 73 | 74 | private: 75 | String fileName; 76 | File *content; 77 | }; 78 | 79 | 80 | class MultipartStream : public Stream { 81 | public: 82 | explicit MultipartStream(HTTPClient *client); 83 | 84 | ~MultipartStream() override; 85 | 86 | size_t predictSize() const; 87 | 88 | void add(MultipartData &newData); 89 | 90 | // API is bast - client must make sure to call last after the last add 91 | void last(); 92 | 93 | int available() override; 94 | 95 | int read() override; 96 | 97 | int peek() override; 98 | 99 | void flush() override; 100 | 101 | size_t write(uint8_t) override; 102 | 103 | size_t readBytes(char *buffer, size_t length) override; 104 | 105 | void setProgressListener(std::function); 106 | 107 | private: 108 | HTTPClient *httpClient; 109 | StreamOfStreams streams; 110 | std::vector myStreams; 111 | String boundary; 112 | size_t length = 0; 113 | }; 114 | 115 | #endif //OPENBIKESENSORFIRMWARE_MULTIPART_H 116 | -------------------------------------------------------------------------------- /src/gpsrecord.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_GPSRECORD_H 25 | #define OPENBIKESENSORFIRMWARE_GPSRECORD_H 26 | 27 | 28 | #include 29 | #include 30 | 31 | class Gps; 32 | 33 | class GpsRecord { 34 | enum GPS_FIX : uint8_t { 35 | NO_FIX = 0, 36 | DEAD_RECKONING_ONLY = 1, 37 | FIX_2D = 2, 38 | FIX_3D = 3, 39 | GPS_AND_DEAD_RECKONING = 4, 40 | TIME_ONLY = 5, 41 | }; 42 | 43 | 44 | 45 | friend Gps; 46 | public: 47 | String getAltitudeMetersString() const; 48 | String getCourseString() const; 49 | String getSpeedKmHString() const; 50 | String getHdopString() const; 51 | String getLatString() const; 52 | String getLongString() const; 53 | bool hasValidFix() const; 54 | double getLatitude() const; 55 | double getLongitude() const; 56 | uint8_t getSatellitesUsed() const; 57 | uint8_t getFixStatusFlags() const; 58 | GPS_FIX getFixStatus() const; 59 | uint32_t getTow() const; 60 | uint32_t getWeek() const; 61 | uint32_t getCreatedAtMillisTicks() const; 62 | 63 | protected: 64 | /* Clear all collected data */ 65 | void reset(uint32_t tow, uint32_t gpsWeek, uint32_t createdAtMillisTicks); 66 | 67 | /* Store tow and related date time data. */ 68 | void setWeek(uint32_t gpsWeek); 69 | 70 | void setPosition(int32_t lon, int32_t lat, int32_t height); 71 | 72 | void setVelocity(uint32_t speedOverGround, int32_t heading); 73 | 74 | void setInfo(uint8_t satellitesInUse, GPS_FIX gpsFix, uint8_t flags); 75 | 76 | void setHdop(uint16_t hDop); 77 | 78 | bool isAllSet() const; 79 | 80 | private: 81 | /* Just the GPS Millisecond time of Week of the record, to be able to 82 | * merge records together. 83 | */ 84 | uint32_t mCollectTow = 0; 85 | uint32_t mCollectWeek = 0; 86 | /* deg, scale 1e-7 */ 87 | int32_t mLongitude; 88 | /* deg, scale 1e-7 */ 89 | int32_t mLatitude; 90 | int mSpeed; // * 100? 91 | int mCourseOverGround; // * 100 92 | int mHdop; // * 100 93 | /* millimeter */ 94 | int32_t mHeight; // * 10? 95 | uint8_t mSatellitesUsed; 96 | GPS_FIX mFixStatus; // 97 | uint8_t mFixStatusFlags; 98 | bool mPositionSet = false; 99 | bool mVelocitySet = false; 100 | bool mInfoSet = false; 101 | bool mHdopSet = false; 102 | uint32_t mCreatedAtMillisTicks; 103 | static const int32_t pow10[10]; 104 | static String toScaledString(int32_t value, uint16_t scale); 105 | }; 106 | 107 | 108 | #endif //OPENBIKESENSORFIRMWARE_GPSRECORD_H 109 | -------------------------------------------------------------------------------- /src/bluetooth/BluetoothManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_BLUETOOTH_BLUETOOTHMANAGER_H 25 | #define OBS_BLUETOOTH_BLUETOOTHMANAGER_H 26 | 27 | #include 28 | #include 29 | 30 | #include "_IBluetoothService.h" 31 | #include "DeviceInfoService.h" 32 | #include "HeartRateService.h" 33 | #include "BatteryService.h" 34 | #include "ObsService.h" 35 | 36 | class BluetoothManager: public BLEServerCallbacks { 37 | public: 38 | /** 39 | * Initializes all defined services and starts the bluetooth server. 40 | */ 41 | void init(const String &obsName, 42 | uint16_t leftOffset, uint16_t rightOffset, 43 | std::function batteryPercentage, 44 | const String &trackId); 45 | 46 | /** 47 | * Starts advertising all services that internally implement shouldAdvertise() 48 | * with `true`. The bluetooth server needs to be started before this method. 49 | */ 50 | void activateBluetooth(); 51 | 52 | /** 53 | * Stops advertising the bluetooth services. The bluetooth server will not be 54 | * stopped. 55 | */ 56 | void deactivateBluetooth() const; 57 | 58 | /** 59 | * Disconnects the currently connected device/client. 60 | */ 61 | void disconnectDevice() const; 62 | 63 | /** 64 | * Processes new sensor values by calling each services with the values. 65 | * @param millis sender millis counter at the time of measurement of the left value 66 | * @param leftValue sensor value of the left side (MAX_SENSOR_VALUE for no reading) 67 | * @param rightValues sensor value of the right side (MAX_SENSOR_VALUE for no reading) 68 | */ 69 | void newSensorValues(uint32_t millis, uint16_t leftValue, uint16_t rightValue); 70 | 71 | /** 72 | * Processes new confirmed pass event. 73 | * @param millis sender millis counter at the time of measurement of the left value 74 | * @param leftValue sensor value of the left side (MAX_SENSOR_VALUE for no reading) 75 | * @param rightValues sensor value of the right side (MAX_SENSOR_VALUE for no reading) 76 | */ 77 | void newPassEvent(uint32_t millis, uint16_t leftValue, uint16_t rightValue); 78 | 79 | /* True if any client is currently connected. */ 80 | bool hasConnectedClients(); 81 | 82 | private: 83 | BLEServer *pServer; 84 | std::list services; 85 | void onDisconnect(BLEServer *pServer) override; 86 | void onConnect(BLEServer *pServer) override; 87 | void setFastAdvertising(); 88 | void setSlowAdvertising(); 89 | bool deviceConnected; 90 | bool fastAdvertising; 91 | uint32_t lastDisconnected; 92 | static const uint32_t HIGH_ADVERTISEMENT_TIME_MS; 93 | 94 | }; 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/utils/streams.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "streams.h" 25 | 26 | // StringStream 27 | 28 | StringStream::StringStream(String str) { 29 | string = std::move(str); 30 | } 31 | 32 | int StringStream::available() { 33 | return string.length() - pos; 34 | } 35 | 36 | int StringStream::read() { 37 | const int result = peek(); 38 | if (result != -1) { 39 | pos++; 40 | } 41 | return result; 42 | } 43 | 44 | int StringStream::peek() { 45 | int result; 46 | if (pos >= string.length()) { 47 | result = -1; 48 | } else { 49 | result = string.charAt(pos); 50 | } 51 | return result; 52 | } 53 | 54 | void StringStream::flush() { 55 | } 56 | 57 | size_t StringStream::write(uint8_t) { 58 | return 0; 59 | } 60 | 61 | size_t StringStream::readBytes(char *buffer, size_t length) { 62 | size_t count; 63 | if (length > available()) { 64 | count = available(); 65 | } else { 66 | count = length; 67 | } 68 | strncpy(buffer, string.c_str(), count); 69 | pos += count; 70 | return count; 71 | } 72 | 73 | // StreamOfStreams 74 | 75 | void StreamOfStreams::push(Stream *addedStream) { 76 | streams.push_back(addedStream); 77 | } 78 | 79 | int StreamOfStreams::available() { 80 | return getCurrent()->available(); 81 | } 82 | 83 | int StreamOfStreams::read() { 84 | const int data = getCurrent()->read(); 85 | if (data >= 0) { 86 | overallBytePos += 1; 87 | if (progressListener) { 88 | progressListener(overallBytePos); 89 | } 90 | } 91 | return data; 92 | } 93 | 94 | int StreamOfStreams::peek() { 95 | return getCurrent()->peek(); 96 | } 97 | 98 | void StreamOfStreams::flush() { 99 | } 100 | 101 | size_t StreamOfStreams::write(uint8_t) { 102 | return 0; 103 | } 104 | 105 | size_t StreamOfStreams::readBytes(char *buffer, size_t length) { 106 | const size_t read = getCurrent()->readBytes(buffer, length); 107 | if (read > 0) { 108 | overallBytePos += read; 109 | if (progressListener) { 110 | progressListener(overallBytePos); 111 | } 112 | } 113 | return read; 114 | } 115 | 116 | void StreamOfStreams::setProgressListener(std::function listener) { 117 | progressListener = listener; 118 | } 119 | 120 | 121 | Stream *StreamOfStreams::getCurrent() { 122 | if (current == nullptr || current->available() == 0) { 123 | current = getNext(); 124 | } 125 | return current; 126 | } 127 | 128 | Stream *StreamOfStreams::getNext() { 129 | if (pos < streams.size()) { 130 | current = streams.at(pos++); 131 | log_d("About to switch to stream %d/%d", pos, streams.size()); 132 | } else { 133 | current = &EMPTY_STREAM; 134 | } 135 | return current; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /src/bluetooth/ObsService.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "ObsService.h" 25 | 26 | const BLEUUID ObsService::OBS_SERVICE_UUID = BLEUUID("1FE7FAF9-CE63-4236-0004-000000000000"); 27 | const BLEUUID ObsService::OBS_TIME_CHARACTERISTIC_UUID = BLEUUID("1FE7FAF9-CE63-4236-0004-000000000001"); 28 | const BLEUUID ObsService::OBS_DISTANCE_CHARACTERISTIC_UUID = BLEUUID("1FE7FAF9-CE63-4236-0004-000000000002"); 29 | const BLEUUID ObsService::OBS_BUTTON_CHARACTERISTIC_UUID = BLEUUID("1FE7FAF9-CE63-4236-0004-000000000003"); 30 | const BLEUUID ObsService::OBS_OFFSET_CHARACTERISTIC_UUID = BLEUUID("1FE7FAF9-CE63-4236-0004-000000000004"); 31 | const BLEUUID ObsService::OBS_TRACK_ID_CHARACTERISTIC_UUID = BLEUUID("1FE7FAF9-CE63-4236-0004-000000000005"); 32 | 33 | ObsService::ObsService(const uint16_t leftOffset, const uint16_t rightOffset, const String &trackId) { 34 | uint8_t offsets[4]; 35 | memcpy(offsets, &leftOffset, 2); 36 | memcpy(&offsets[2], &rightOffset, 2); 37 | mOffsetCharacteristic.setValue(offsets, 4); 38 | mTrackIdCharacteristic.setValue(trackId.c_str()); 39 | } 40 | 41 | void ObsService::setup(BLEServer *pServer) { 42 | // Each characteristic needs 2 handles and descriptor 1 handle. 43 | mService = pServer->createService(OBS_SERVICE_UUID); // Keep the default, 18); 44 | 45 | mService->addCharacteristic(&mTimeCharacteristic); 46 | mTimeCharacteristic.setCallbacks(&mTimeCharacteristicsCallback); 47 | 48 | mService->addCharacteristic(&mDistanceCharacteristic); 49 | mDistanceCharacteristic.addDescriptor(&mDistanceConfiguration); 50 | 51 | mService->addCharacteristic(&mButtonCharacteristic); 52 | mButtonCharacteristic.addDescriptor(new BLE2902); 53 | 54 | mService->addCharacteristic(&mOffsetCharacteristic); 55 | 56 | mService->addCharacteristic(&mTrackIdCharacteristic); 57 | } 58 | 59 | bool ObsService::shouldAdvertise() { 60 | return true; 61 | } 62 | 63 | BLEService* ObsService::getService() { 64 | return mService; 65 | } 66 | 67 | void ObsService::newSensorValues(uint32_t millis, uint16_t leftValue, uint16_t rightValue) { 68 | if (mDistanceConfiguration.getNotifications()) { 69 | sendEventData(&mDistanceCharacteristic, millis, leftValue, rightValue); 70 | } 71 | } 72 | 73 | void ObsService::newPassEvent(uint32_t millis, uint16_t leftValue, uint16_t rightValue) { 74 | sendEventData(&mButtonCharacteristic, millis, leftValue, rightValue); 75 | } 76 | 77 | void ObsTimeServiceCallback::onRead(BLECharacteristic *pCharacteristic) { 78 | uint32_t value = millis(); 79 | pCharacteristic->setValue(value); 80 | } 81 | 82 | void ObsService::sendEventData(BLECharacteristic *characteristic, uint32_t millis, uint16_t leftValue, uint16_t rightValue) { 83 | uint8_t event[8]; 84 | memcpy(event, &millis, sizeof(millis)); 85 | if (leftValue == MAX_SENSOR_VALUE) { 86 | leftValue = 0xffff; 87 | } 88 | memcpy(&event[4], &leftValue, sizeof(leftValue)); 89 | if (rightValue == MAX_SENSOR_VALUE) { 90 | rightValue = 0xffff; 91 | } 92 | memcpy(&event[6], &rightValue, sizeof(rightValue)); 93 | characteristic->setValue(event, 8); 94 | characteristic->notify(); 95 | } 96 | -------------------------------------------------------------------------------- /src/utils/obsutils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "obsutils.h" 25 | #include 26 | #include "writer.h" 27 | #include "BLEServer.h" 28 | 29 | static const uint32_t BYTES_PER_KIB = 1 << 10; 30 | static const uint32_t BYTES_PER_MIB = 1 << 20; 31 | static const uint32_t BYTES_PER_GIB = 1 << 30; 32 | 33 | String ObsUtils::createTrackUuid() { 34 | uint8_t data[16]; 35 | esp_fill_random(data, 16); 36 | return String(BLEUUID(data, 16, false).toString().c_str()); 37 | } 38 | 39 | String ObsUtils::stripCsvFileName(const String &fileName) { 40 | String userPrintableFilename = fileName.substring(fileName.lastIndexOf("/") + 1); 41 | if (userPrintableFilename.endsWith(CSVFileWriter::EXTENSION)) { 42 | userPrintableFilename 43 | = userPrintableFilename.substring( 44 | 0, userPrintableFilename.length() - CSVFileWriter::EXTENSION.length()); 45 | } 46 | return userPrintableFilename; 47 | } 48 | 49 | String ObsUtils::encodeForXmlAttribute(const String &text) { 50 | String result(text); 51 | result.replace("&", "&"); 52 | result.replace("<", "<"); 53 | result.replace(">", ">"); 54 | result.replace("'", "'"); 55 | result.replace("\"", """); 56 | return result; 57 | } 58 | 59 | String ObsUtils::encodeForXmlText(const String &text) { 60 | String result(text); 61 | result.replace("&", "&"); 62 | result.replace("<", "<"); 63 | return result; 64 | } 65 | 66 | String ObsUtils::encodeForCsvField(const String &field) { 67 | String result(field); 68 | result.replace(';', '_'); 69 | result.replace('\n', ' '); 70 | result.replace('\r', ' '); 71 | return result; 72 | } 73 | 74 | // Poor man.... 75 | String ObsUtils::encodeForUrl(const String &url) { 76 | String result(url); 77 | result.replace("%", "%25"); 78 | result.replace("+", "%2B"); 79 | result.replace(" ", "+"); 80 | result.replace("\"", "%22"); 81 | result.replace("\'", "%27"); 82 | result.replace("=", "%3D"); 83 | return result; 84 | } 85 | 86 | String ObsUtils::toScaledByteString(uint64_t size) { 87 | String result; 88 | if (size <= BYTES_PER_KIB * 10) { 89 | result = String((uint32_t) size) + "B"; 90 | } else if (size <= BYTES_PER_MIB * 10) { 91 | result = String((uint32_t) (size >> 10)) + "KiB"; 92 | } else if (size <= BYTES_PER_GIB * 10) { 93 | result = String((uint32_t) (size >> 20)) + "MiB"; 94 | } else { 95 | result = String((uint32_t) (size >> 30)) + "GiB"; 96 | } 97 | return result; 98 | } 99 | 100 | void ObsUtils::logHexDump(const uint8_t *buffer, uint16_t length) { 101 | ESP_LOG_BUFFER_HEXDUMP(__FILE__, buffer, length, ESP_LOG_WARN); 102 | } 103 | 104 | String ObsUtils::sha256ToString(byte *sha256) { 105 | const int HASH_LEN = 32; 106 | char hash_print[HASH_LEN * 2 + 1]; 107 | hash_print[HASH_LEN * 2] = 0; 108 | for (int i = 0; i < HASH_LEN; ++i) { 109 | snprintf(&hash_print[i * 2], 3, "%02x", sha256[i]); 110 | } 111 | return String(hash_print); 112 | } 113 | 114 | String ObsUtils::to3DigitString(uint32_t value) { 115 | String val = String(value); 116 | if (value <= 9) { 117 | val = "00" + val; 118 | } else if (value >= 10 && value <= 99) { 119 | val = "0" + val; 120 | } // no overflow 121 | return val; 122 | } -------------------------------------------------------------------------------- /docs/software/firmware/obs_cfg.md: -------------------------------------------------------------------------------- 1 | # OpenBikeSensor configuration 2 | 3 | This file describes the configuration format of the OBS internal(!) 4 | configuration file. Please note that even that the format seems well 5 | documented, it is considered an internal format which might change at 6 | any time. There might be interpretations possible in which case 7 | the current implementation defines the correct used. 8 | 9 | The configuration is prepared for extension to support configuration 10 | presets, where certain values of the "default" configuration can be 11 | changed for a certain presets. The handle bar offsets are very likely 12 | candidates for this. The Wi-Fi or Portal configuration is more likely 13 | not part of a presets. 14 | 15 | When working with backups please note that the configuration file contains 16 | your Wi-Fi password, and the portal token in plain text. 17 | Both values are secrets that should not be disclosed, so keep the backup 18 | at a save place and replace these values when sharing. 19 | 20 | ## cfg.obs 21 | 22 | Use the annotated sample file as documentation, order of the keys is not 23 | relevant put the order of the array content. 24 | 25 | ```json5 26 | { 27 | // obs must be an array. It can contain possibly multiple entries, 28 | // the 1st defines default values for all presets, and the default presets. 29 | "obs": [ 30 | { 31 | // enables / disables bluetooth 32 | "bluetooth": true, 33 | // time window for overtake measurement confirmation 34 | "confirmationTimeSeconds": 4, 35 | // Bitfield display config, see DisplayOptions for details, 36 | // as noted all subject to change! 37 | "displayConfig": 15, 38 | // PIN to be entered when accessing the OBS web interface. 39 | // a new one will be created when empty. The PIN is also displayed 40 | // on the OBS display when needed. 41 | "httpPin": "12345678", 42 | // Textual name of the profile - waiting for features to come. 43 | "name": "default", 44 | // Name of the OBS, will be used for WiFo, Bluetooth and other places 45 | // currently no way to change it, consists of OpenBikeSensor- 46 | "obsName": "OpenBikeSensor-cafe", 47 | // The handle bar offset in cm, order right, left. 48 | "offset": [ 49 | 31, 50 | 32 51 | ], 52 | // Token used to authenticate and authorize at the portal. 53 | "portalToken": "thisIsAlsoSecret", 54 | // URL of the portal to be used 55 | "portalUrl": "https://portal.openbikesensor.org", 56 | // Array with privacy areas to be considered 57 | "privacyArea": [ 58 | { 59 | // latitude of the entered value, for documentation and display purpose only 60 | "lat": 48.001, 61 | // shifted latitude used for position filtering 62 | "latT": 48.00105, 63 | // longitude of the entered value, for documentation and display purpose only 64 | "long": 9.001, 65 | // shifted longitude used for position filtering 66 | "longT": 9.001121, 67 | // radius in meters around the position to be filtered 68 | "radius": 101 69 | } 70 | ], 71 | // Bitfield for the privacy configuration see PrivacyOptions 72 | "privacyConfig": 10, 73 | // Active preset - always 0 as of today 74 | "selectedPreset": 0, 75 | // Deprecated: Password of your Wi-Fi where the OBS should log into in server mode 76 | "wifiPassword": "swordfish", 77 | // Deprecated: SSID of your Wi-Fi where the OBS should log into in server mode 78 | "wifiSsid": "obs-cloud", 79 | // Array with multiple Wi-Fi networks to be used in client mode 80 | "wifiNetworks": [ 81 | { 82 | // Password of your Wi-Fi where the OBS should log into in client mode 83 | "wifiPassword": "swordfish", 84 | // SSID of your Wi-Fi where the OBS should log into in client mode 85 | "wifiSsid": "obs-cloud", 86 | // if true obs will allow unprotected access in this network 87 | "wifiPrivate": true 88 | } 89 | ] 90 | } 91 | ] 92 | } 93 | ``` 94 | 95 | -------------------------------------------------------------------------------- /src/gpsrecord.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "gpsrecord.h" 25 | 26 | void GpsRecord::reset(uint32_t tow, uint32_t gpsWeek, uint32_t createdAtMillisTicks) { 27 | mCollectTow = tow; 28 | mCollectWeek = gpsWeek; 29 | mCreatedAtMillisTicks = createdAtMillisTicks; 30 | mLatitude = 0; 31 | mLongitude = 0; 32 | mCourseOverGround = 0; 33 | mSatellitesUsed = 0; 34 | mFixStatus = GPS_FIX::NO_FIX; 35 | mFixStatusFlags = 0; 36 | mHdop = 0; 37 | mHeight = 0; 38 | mSpeed = 0; 39 | mPositionSet = false; 40 | mVelocitySet = false; 41 | mInfoSet = false; 42 | mHdopSet = false; 43 | } 44 | 45 | void GpsRecord::setWeek(uint32_t week) { 46 | mCollectWeek = week; 47 | } 48 | 49 | void GpsRecord::setPosition(int32_t lon, int32_t lat, int32_t height) { 50 | mLongitude = lon; 51 | mLatitude = lat; 52 | mHeight = height; 53 | mPositionSet = true; 54 | } 55 | 56 | void GpsRecord::setVelocity(uint32_t speedOverGround, int32_t heading) { 57 | mSpeed = speedOverGround; 58 | mCourseOverGround = heading; 59 | mVelocitySet = true; 60 | } 61 | 62 | void GpsRecord::setInfo(uint8_t satellitesInUse, GPS_FIX gpsFix, uint8_t flags) { 63 | mSatellitesUsed = satellitesInUse; 64 | mFixStatus = gpsFix; 65 | mFixStatusFlags = flags; 66 | mInfoSet = true; 67 | } 68 | 69 | void GpsRecord::setHdop(uint16_t hDop) { 70 | mHdop = hDop; 71 | mHdopSet = true; 72 | } 73 | 74 | bool GpsRecord::isAllSet() const { 75 | return mPositionSet && mVelocitySet && mInfoSet && mHdopSet; 76 | } 77 | 78 | uint32_t GpsRecord::getTow() const { 79 | return mCollectTow; 80 | } 81 | 82 | uint32_t GpsRecord::getWeek() const { 83 | return mCollectWeek; 84 | } 85 | 86 | String GpsRecord::getAltitudeMetersString() const { 87 | // 3 digits is problematic, 2 are enough any way. 88 | return toScaledString((mHeight + 5) / 10, 2); 89 | } 90 | 91 | String GpsRecord::getCourseString() const { 92 | return toScaledString(mCourseOverGround, 5); 93 | } 94 | 95 | String GpsRecord::getSpeedKmHString() const { 96 | return toScaledString((mSpeed * 60 * 60) / 10000, 1); 97 | } 98 | 99 | String GpsRecord::getHdopString() const { 100 | return toScaledString(mHdop, 2); 101 | } 102 | 103 | 104 | const int32_t GpsRecord::pow10[] = { 105 | 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 106 | }; 107 | 108 | String GpsRecord::toScaledString(const int32_t value, const uint16_t scale) { 109 | if (value == 0) { 110 | return ""; 111 | } 112 | char buffer[32]; 113 | const int32_t scl = pow10[scale]; 114 | snprintf(buffer, sizeof(buffer), "%d.%0*d", value / scl, scale, abs(value % scl) ); 115 | return String(buffer); 116 | } 117 | 118 | bool GpsRecord::hasValidFix() const { 119 | return (mFixStatus == FIX_2D || mFixStatus == FIX_3D || mFixStatus == GPS_AND_DEAD_RECKONING) 120 | && mHdop != 9999 && mSatellitesUsed != 0; 121 | } 122 | 123 | String GpsRecord::getLatString() const { 124 | return toScaledString(mLatitude, 7); 125 | } 126 | 127 | String GpsRecord::getLongString() const { 128 | return toScaledString(mLongitude, 7); 129 | } 130 | 131 | double GpsRecord::getLatitude() const { 132 | return ((double) mLatitude) / 10000000.0; 133 | } 134 | 135 | double GpsRecord::getLongitude() const { 136 | return ((double) mLongitude) / 10000000.0; 137 | } 138 | 139 | uint8_t GpsRecord::getSatellitesUsed() const { 140 | return mSatellitesUsed; 141 | } 142 | 143 | GpsRecord::GPS_FIX GpsRecord::getFixStatus() const { 144 | return mFixStatus; 145 | } 146 | 147 | uint32_t GpsRecord::getCreatedAtMillisTicks() const { 148 | return mCreatedAtMillisTicks; 149 | } 150 | 151 | uint8_t GpsRecord::getFixStatusFlags() const { 152 | return mFixStatusFlags; 153 | } 154 | -------------------------------------------------------------------------------- /src/fonts/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | https://openfontlicense.org 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /docs/software/firmware/bluetooth_services.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Bluetooth Services 4 | parent: Firmware 5 | grand_parent: Software 6 | --- 7 | 8 | # Overview 9 | 10 | | Service | UUID | Description | 11 | | ----------- | -------------------------------------- | ------------------------------------------------------------------ | 12 | | Device Info | `0000180A-0000-1000-8000-00805F9B34FB` | General information about the bluetooth device | 13 | | OBS | `1FE7FAF9-CE63-4236-0004-000000000000` | Reports distance sensor readings and confirmed close passes | 14 | | Heart Rate | `0000180D-0000-1000-8000-00805F9B34FB` | Transmits the current distance by acting like a heart rate monitor | 15 | 16 | 17 | ## Device Info Service 18 | - *Description:* General information about the bluetooth device 19 | - *UUID:* `0000180A-0000-1000-8000-00805F9B34FB` 20 | 21 | | Characteristic | UUID | Property | Value | 22 | | ----------------- | -------------------------------------- | -------- | ------------------ | 23 | | Firmware Revision | `00002a26-0000-1000-8000-00805f9b34fb` | `READ` | `vX.Y.ZZZZ` | 24 | | Manufacturer Name | `00002a29-0000-1000-8000-00805f9b34fb` | `READ` | `openbikesensor.org` | 25 | 26 | 27 | ## OBS Service 28 | - *Description:* Transmits current sensor readings 29 | - *UUID:* `1FE7FAF9-CE63-4236-0004-000000000000` 30 | 31 | | Characteristic | UUID | Property | Value | 32 | | ------------------- | -------------------------------------- | --------------- | ----------------------------------------------------------------------------------- | 33 | | Time | `1FE7FAF9-CE63-4236-0004-000000000001` | `READ` | reports the value of the ms timer of the OBS unit, can be used to synchronize time | 34 | | Sensor Distance | `1FE7FAF9-CE63-4236-0004-000000000002` | `NOTIFY` | Gives sensor reading of the left and right sensor. | 35 | | Close Pass | `1FE7FAF9-CE63-4236-0004-000000000003` | `NOTIFY` | Notifies of button confirmed close pass events. | 36 | | Offset | `1FE7FAF9-CE63-4236-0004-000000000004` | `READ` | Configured handle bar offset values in cm. | 37 | | Track Id | `1FE7FAF9-CE63-4236-0004-000000000005` | `READ` | UUID as text to uniquely identify the current recorded track. | 38 | 39 | This service uses binary format to transfer time counter as unit32 and unt16 40 | for distance in cm. 41 | 42 | *Time* is sent as uint32. The time counts linear milliseconds from the start 43 | of the obs. The value returned is the timer value at the time of the read. 44 | 45 | *Sensor Distance* delivers the time of the left measurement with the current values of 46 | the left and right sensor. Content is time uint32, left uint16, right uint16. Left 47 | and right values are in cm, a value of `0xffff` means no measurement. The message is 48 | sent immediately after the measure, so you can assume that the reported time 49 | is current at the ESP. 50 | 51 | *Close Pass* events are triggered when a pass was confirmed by button press. The 52 | values are same as with the *Sensor Distance* characteristic. Note that this 53 | information is sent after confirmation, so the timer information must be used 54 | to match the event to the correct time and so location. 55 | 56 | *Offset* reports the configured handle bar offsets in cm on the OBS side. This 57 | is purely to ease the user configuration. The offset is not considered in any 58 | of the other reported values. The service uses 2 uint16 values to report the 59 | left and right offset in cm in that order. 60 | 61 | *Tack Id* holds a UUID as String representation that can be used to uniquely 62 | identify the recorded track. If the value changes, a new track is recorded, and 63 | the millisecond counter on the OBS likely is restarted. 64 | 65 | ## Heart Rate Service 66 | - *Description:* Transmits the current distance by acting like a heart rate monitor 67 | - *UUID:* `0000180D-0000-1000-8000-00805F9B34FB` 68 | 69 | | Characteristic | UUID | Property | Value | 70 | | --------------- | -------------------------------------- | ---------------- | ----------------------------------------- | 71 | | Heart Rate | `00002a37-0000-1000-8000-00805f9b34fb` | `NOTIFY` | Minimum distance measured over 1/2 second | 72 | 73 | -------------------------------------------------------------------------------- /src/utils/multipart.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "multipart.h" 25 | 26 | MultipartData::MultipartData(String name, String contentType) { 27 | this->name = std::move(name); 28 | this->contentType = std::move(contentType); 29 | } 30 | 31 | String MultipartData::getBaseHeaders(const String& fileName) { 32 | String headers = "Content-Disposition: form-data; name=\"" + name + "\""; 33 | if (!fileName.isEmpty()) { 34 | headers += "; filename=\"" + fileName + "\""; 35 | } 36 | headers += "\r\n"; 37 | if (!contentType.isEmpty()) { 38 | headers += "Content-Type: " + contentType + "\r\n"; 39 | } 40 | return headers; 41 | } 42 | 43 | 44 | MultipartDataString::MultipartDataString(String name, const String& content, String contentType) 45 | : MultipartData(std::move(name), std::move(contentType)), contentStream(content) { 46 | this->content = content; 47 | } 48 | 49 | String MultipartDataString::getHeaders() { 50 | return getBaseHeaders(); 51 | } 52 | 53 | Stream *MultipartDataString::asStream() { 54 | return & 55 | contentStream; 56 | } 57 | 58 | size_t MultipartDataString::length() { 59 | return content.length(); 60 | 61 | } 62 | 63 | String MultipartDataStream::getHeaders() { 64 | return getBaseHeaders(fileName); 65 | } 66 | 67 | Stream *MultipartDataStream::asStream() { 68 | return content; 69 | } 70 | 71 | size_t MultipartDataStream::length() { 72 | return content->size(); 73 | } 74 | 75 | MultipartDataStream::MultipartDataStream(String name, String fileName, File *content, String contentType) 76 | : MultipartData(std::move(name), std::move(contentType)) { 77 | this->fileName = std::move(fileName); 78 | this->content = content; 79 | } 80 | 81 | 82 | MultipartStream::MultipartStream(HTTPClient *client) { 83 | this->httpClient = client; 84 | boundary = "----" + String(esp_random(), 16) + String(esp_random(), 16); 85 | httpClient->addHeader("Content-Type", 86 | "multipart/form-data; boundary=" + boundary); 87 | } 88 | 89 | MultipartStream::~MultipartStream() { 90 | for (const auto stream : myStreams) { 91 | delete stream; 92 | } 93 | myStreams.clear(); 94 | } 95 | 96 | size_t MultipartStream::predictSize() const { 97 | return length; 98 | } 99 | 100 | void MultipartStream::add(MultipartData &newData) { 101 | String preamble = "\r\n--" + boundary + "\r\n" 102 | + newData.getHeaders() + "\r\n"; 103 | Stream *preambleStream = new StringStream(preamble); 104 | streams.push(preambleStream); 105 | myStreams.push_back(preambleStream); 106 | streams.push(newData.asStream()); 107 | length += preamble.length(); 108 | length += newData.length(); 109 | log_d("Adding new part, size: %d", newData.length()); 110 | } 111 | 112 | // API is bad - client must make sure to call last after the last add 113 | void MultipartStream::last() { 114 | String conclusion = "\r\n--" + boundary + "--\r\n"; 115 | Stream *conclusionStream = new StringStream(conclusion); 116 | streams.push(conclusionStream); 117 | myStreams.push_back(conclusionStream); 118 | length += conclusion.length(); 119 | } 120 | 121 | int MultipartStream::available() { 122 | return streams.available(); 123 | } 124 | 125 | int MultipartStream::read() { 126 | return streams.read(); 127 | } 128 | 129 | int MultipartStream::peek() { 130 | return streams.peek(); 131 | } 132 | 133 | void MultipartStream::flush() { 134 | } 135 | 136 | size_t MultipartStream::write(uint8_t) { 137 | return 0; 138 | } 139 | 140 | size_t MultipartStream::readBytes(char *buffer, size_t readLength) { 141 | return streams.readBytes(buffer, readLength); 142 | } 143 | 144 | void MultipartStream::setProgressListener(std::function listener) { 145 | streams.setProgressListener(listener); 146 | } 147 | -------------------------------------------------------------------------------- /src/VoltageMeter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "VoltageMeter.h" 25 | #include "globals.h" 26 | 27 | /* Class to encapsulate voltage readings and smoothing thereof. 28 | * Still the values are not as accurate as expected, and it is not 29 | * clear if this is a error in the code or limitation of the ESP. 30 | * I read() 3.96V for 4.02V on my cheep voltage meter. 31 | * 32 | * We might add features like a trend (charging/discharging) and 33 | * possibly guess percentage later. We also need a "alert" threshold 34 | * where we just save all end exit. 35 | * Using ESP32 calls not arduino lib calls here. 36 | * ESPCode: https://github.com/espressif/esp-idf/blob/master/components/esp_adc_cal/include/esp_adc_cal.h 37 | */ 38 | VoltageMeter::VoltageMeter(uint8_t batteryPin, adc1_channel_t channel) : 39 | mBatteryPin(batteryPin), mBatteryAdcChannel(channel) { 40 | log_i("Initializing VoltageMeter."); 41 | pinMode(mBatteryPin, INPUT); 42 | ESP_ERROR_CHECK_WITHOUT_ABORT( 43 | adc1_config_width(ADC_WIDTH_BIT_12)); 44 | // Suggested range for ADC_ATTEN_DB_11 is 150 - 2450 mV, we are a bit above 4.22V * 2/3 == 2.81V 45 | // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html#api-reference 46 | ESP_ERROR_CHECK_WITHOUT_ABORT( 47 | adc1_config_channel_atten(mBatteryAdcChannel, ADC_ATTEN_DB_11)); 48 | __unused const esp_adc_cal_value_t val_type = esp_adc_cal_characterize( 49 | ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 50 | REF_VOLTAGE_MILLI_VOLT, &adc_chars); 51 | if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { 52 | log_i("Characterized using Two Point Value"); 53 | } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) { 54 | log_i("Characterized using eFuse Vref"); 55 | } else { 56 | log_i("Characterized using Default Vref"); 57 | } 58 | //Check if TP is burned into eFuse 59 | if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { 60 | log_i("eFuse Two Point: Supported"); 61 | } else { 62 | log_i("eFuse Two Point: NOT supported"); 63 | } 64 | //Check Vref is burned into eFuse 65 | if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) { 66 | log_i("eFuse Vref: Supported"); 67 | } else { 68 | log_i("eFuse Vref: NOT supported"); 69 | } 70 | lastSmoothedReading = readRaw(); 71 | for (int i = 0; i < MINIMUM_SAMPLES; i++) { 72 | readSmoothed(); 73 | yield(); 74 | } 75 | log_i("VoltageMeter initialized got %03.2fV.", read()); 76 | } 77 | 78 | bool VoltageMeter::isWarningLevel() { 79 | return hasReadings() && (read() < VoltageMeter::BATTERY_WARNING_LEVEL); 80 | } 81 | 82 | bool VoltageMeter::hasReadings() { 83 | return read() > VoltageMeter::BATTERY_NO_READ_LEVEL; 84 | } 85 | 86 | double VoltageMeter::read() { 87 | return esp_adc_cal_raw_to_voltage(readSmoothed(), &adc_chars) 88 | * 3.0 / 2000.0; // voltage divider @ OSB PCB 89 | } 90 | 91 | int8_t VoltageMeter::readPercentage() { 92 | if (!hasReadings()) { 93 | return -1; 94 | } 95 | auto voltage = read(); 96 | int8_t percentage; 97 | if (voltage > 4.13) { 98 | percentage = 100; 99 | } else if (voltage > 3.67) { // 100% - 50% 100 | percentage = 108.696 * voltage - 348.914; 101 | } else if (voltage > 3.49) { // 50% - 25% 102 | percentage = 138.889 * voltage - 459.723; 103 | } else if (voltage > 3.12) { // 25% - 0% 104 | percentage = 67.568 * voltage - 210.812; 105 | } else { 106 | percentage = 0; 107 | } 108 | log_v("VoltageMeter: %.2fV %d%%", voltage, percentage); 109 | return percentage; 110 | } 111 | 112 | int VoltageMeter::readSmoothed() { 113 | lastSmoothedReading = 114 | (lastSmoothedReading * (SAMPLES_DIVIDE - 1) + readRaw()) / SAMPLES_DIVIDE; 115 | return lastSmoothedReading; 116 | } 117 | 118 | int VoltageMeter::readRaw() const { 119 | return adc1_get_raw(mBatteryAdcChannel); 120 | } 121 | -------------------------------------------------------------------------------- /src/uploader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "uploader.h" 25 | 26 | #include "globals.h" 27 | #include "utils/multipart.h" 28 | #include "utils/timeutils.h" 29 | #include "writer.h" 30 | 31 | // https://docs.platformio.org/en/latest/platforms/espressif32.html#embedding-binary-data 32 | extern const uint8_t x509_crt_bundle_start[] asm("_binary_src_truststore_x509_crt_bundle_start"); 33 | 34 | static char const *const HTTP_LOCATION_HEADER = "location"; 35 | 36 | Uploader::Uploader(String portalUrl, String userToken) : 37 | mPortalUrl(std::move(portalUrl)), 38 | mPortalUserToken(std::move(userToken)) { 39 | TimeUtils::setClockByNtpAndWait(); 40 | mWiFiClient.setCACertBundle(x509_crt_bundle_start); 41 | } 42 | 43 | /* Upload file as track data to "The Portal" as multipart form data. 44 | */ 45 | bool Uploader::upload(const String& fileName) { 46 | bool success = false; 47 | if(fileName.substring(0,7) != "/sensor" 48 | && !fileName.endsWith(CSVFileWriter::EXTENSION)) { 49 | log_e("Not sending %s wrong extension.", fileName.c_str()); 50 | mLastStatusMessage = "Not sending " + fileName + " wrong extension."; 51 | } else { 52 | log_d("Sending '%s'.", fileName.c_str()); 53 | File csvFile = SD.open(fileName.c_str(), "r"); 54 | if (csvFile) { 55 | success = uploadFile(csvFile); 56 | csvFile.close(); 57 | } else { 58 | log_e("file %s not found", fileName.c_str()); 59 | mLastStatusMessage = "File " + fileName + " not found!"; 60 | } 61 | } 62 | return success; 63 | } 64 | 65 | bool Uploader::uploadFile(File &file) { 66 | bool success = false; 67 | HTTPClient https; 68 | https.setTimeout(30 * 1000); // give the api some time 69 | https.setUserAgent(String("OBS/") + String(OBSVersion)); 70 | 71 | const char* headers[] = { HTTP_LOCATION_HEADER }; 72 | https.collectHeaders(headers, 1); 73 | if (https.begin(mWiFiClient, mPortalUrl + "/api/tracks")) { // HTTPS 74 | https.addHeader("Authorization", "OBSUserId " + mPortalUserToken); 75 | https.addHeader("Content-Type", "application/json"); 76 | const String fileName = file.name(); 77 | const String displayFileName = ObsUtils::stripCsvFileName(fileName); 78 | MultipartStream mp(&https); 79 | MultipartDataString title("title", "AutoUpload " + displayFileName); 80 | mp.add(title); 81 | MultipartDataString description("description", "Uploaded with OpenBikeSensor " + String(OBSVersion)); 82 | mp.add(description); 83 | MultipartDataStream data("body", fileName, &file, "text/csv"); 84 | mp.add(data); 85 | mp.last(); 86 | const size_t contentLength = mp.predictSize(); 87 | mp.setProgressListener([contentLength](size_t pos) { 88 | obsDisplay->drawProgressBar(5, pos, contentLength); 89 | }); 90 | 91 | int httpCode = https.sendRequest("POST", &mp, contentLength); 92 | 93 | mLastStatusMessage = String(httpCode) + ": "; 94 | if (httpCode < 0) { 95 | mLastStatusMessage += HTTPClient::errorToString(httpCode); 96 | // This might be a large body, could be any wrong web url configured! 97 | } else if (https.getSize() < 1024) { 98 | mLastStatusMessage += https.getString(); 99 | } else { 100 | mLastStatusMessage += "Length: " + String(https.getSize()); 101 | } 102 | mLastLocation = https.header(HTTP_LOCATION_HEADER); 103 | if (httpCode == 200 || httpCode == 201) { 104 | log_v("HTTP OK %s", mLastStatusMessage.c_str()); 105 | success = true; 106 | } else { 107 | log_e("HTTP Error %s", mLastStatusMessage.c_str()); 108 | https.end(); 109 | } 110 | } else { 111 | mLastStatusMessage = "[HTTPS] begin to " + mPortalUrl + " failed."; 112 | log_e("HTTPS error %s", mLastStatusMessage.c_str()); 113 | https.end(); 114 | } 115 | return success; 116 | } 117 | 118 | String Uploader::getLastStatusMessage() const { 119 | return mLastStatusMessage; 120 | } 121 | 122 | String Uploader::getLastLocation() const { 123 | return mLastLocation; 124 | } 125 | -------------------------------------------------------------------------------- /src/bluetooth/BluetoothManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "BluetoothManager.h" 25 | 26 | const uint32_t BluetoothManager::HIGH_ADVERTISEMENT_TIME_MS = 60 * 1000; 27 | 28 | void BluetoothManager::init( 29 | const String &obsName, 30 | const uint16_t leftOffset, const uint16_t rightOffset, 31 | std::function batteryPercentage, 32 | const String &trackId) { 33 | 34 | deviceConnected = false; 35 | ESP_ERROR_CHECK_WITHOUT_ABORT( 36 | esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); 37 | BLEDevice::init(obsName.c_str()); 38 | pServer = BLEDevice::createServer(); 39 | pServer->setCallbacks(this); 40 | 41 | services.push_back(new DeviceInfoService); 42 | services.push_back(new HeartRateService); 43 | services.push_back(new BatteryService(batteryPercentage)); 44 | services.push_back(new ObsService(leftOffset, rightOffset, trackId)); 45 | 46 | for (auto &service : services) { 47 | service->setup(pServer); 48 | } 49 | for (auto &service : services) { 50 | service->getService()->start(); 51 | } 52 | lastDisconnected = millis(); 53 | } 54 | 55 | void BluetoothManager::activateBluetooth() { 56 | auto adv = pServer->getAdvertising(); 57 | 58 | // only the heard rate service && OBS service use advertisement 59 | // if I add one more service the 0x12 info is not sent. 60 | for (auto &service : services) { 61 | if (service->shouldAdvertise()) { 62 | adv->addServiceUUID(service->getService()->getUUID()); 63 | } 64 | } 65 | setFastAdvertising(); 66 | 67 | // Save some bytes in the advertising payload 68 | // https://specificationrefs.bluetooth.com/assigned-values/Appearance%20Values.pdf 69 | // adv->setAppearance(1152); // Generic: Cycling 70 | 71 | // causes 0x12 Slave Connection Interval Range to be sent 72 | adv->setMinPreferred(0x06); // Apple? 73 | adv->setMaxPreferred(0x12); 74 | 75 | BLEDevice::startAdvertising(); 76 | } 77 | 78 | void BluetoothManager::deactivateBluetooth() const { 79 | pServer->getAdvertising()->stop(); 80 | } 81 | 82 | void BluetoothManager::disconnectDevice() const { 83 | pServer->disconnect(pServer->getConnId()); 84 | } 85 | 86 | void BluetoothManager::newSensorValues(const uint32_t millis, const uint16_t leftValues, const uint16_t rightValues) { 87 | if (deviceConnected) { 88 | for (auto &service : services) { 89 | service->newSensorValues(millis, leftValues, rightValues); 90 | } 91 | } else if (lastDisconnected + HIGH_ADVERTISEMENT_TIME_MS < millis) { 92 | setSlowAdvertising(); 93 | } 94 | } 95 | 96 | void BluetoothManager::newPassEvent(const uint32_t millis, const uint16_t leftValue, const uint16_t rightValue) { 97 | log_i("BLE new pass event at %d, left: %dcm, right: %dcm", millis, leftValue, rightValue); 98 | if (deviceConnected) { 99 | for (auto &service : services) { 100 | service->newPassEvent(millis, leftValue, rightValue); 101 | } 102 | } 103 | } 104 | 105 | bool BluetoothManager::hasConnectedClients() { 106 | return pServer->getConnectedCount() != 0; 107 | } 108 | 109 | void BluetoothManager::onConnect(BLEServer* pServer) { 110 | log_i("BTLE connected!"); 111 | deviceConnected = true; 112 | }; 113 | 114 | void BluetoothManager::onDisconnect(BLEServer* pServer) { 115 | log_i("BTLE disconnected!"); 116 | lastDisconnected = millis(); 117 | deviceConnected = false; 118 | setFastAdvertising(); 119 | pServer->startAdvertising(); 120 | } 121 | 122 | void BluetoothManager::setFastAdvertising() { 123 | auto adv = pServer->getAdvertising(); 124 | adv->setMinInterval(48 /* 0.625 msec = 30ms */); 125 | adv->setMaxInterval(80 /* 0.625 msec = 50ms */); 126 | fastAdvertising = true; 127 | } 128 | 129 | void BluetoothManager::setSlowAdvertising() { 130 | if (fastAdvertising) { 131 | log_i("Decreasing BTLE advertisement interval."); 132 | auto adv = pServer->getAdvertising(); 133 | adv->stop(); 134 | adv->setMinInterval(800 /* 0.625 msec = 500ms */); 135 | adv->setMaxInterval(1280 /* 0.625 msec = 800ms */); 136 | adv->start(); 137 | fastAdvertising = false; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/sensor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_SENSOR_H 25 | #define OBS_SENSOR_H 26 | 27 | #include 28 | #include 29 | 30 | #include "variant.h" 31 | #include "globals.h" 32 | #include "utils/median.h" 33 | 34 | /* About the speed of sound: 35 | See also http://www.sengpielaudio.com/Rechner-schallgeschw.htm (german) 36 | - speed of sound depends on ambient temperature 37 | temp, Celsius speed, m/sec int factor dist error introduced with fix int factor of 58 38 | (331.5+(0.6*t)) (2000/speed) (speed@58 / speed) - 1 39 | 35 352.1 (57) -2.1% (-3.2cm bei 150cm) 40 | 30 349.2 41 | 25 346.3 42 | 22.4 344.82 58 0 43 | 20 343.4 44 | 15 340.5 45 | 12.5 338.98 (59) +1.7% (2.6cm bei 150) 46 | 10 337.5 47 | 5 334.5 48 | 0 331.5 (60) +4% (6cm bei 150cm) 49 | −5 328.5 50 | −10 325.4 51 | −15 322.3 52 | */ 53 | 54 | struct HCSR04SensorInfo { 55 | uint8_t triggerPin = 15; 56 | uint8_t echoPin = 4; 57 | uint16_t offset = 0; 58 | uint16_t rawDistance = 0; 59 | uint16_t distances[MEDIAN_DISTANCE_MEASURES] = { MAX_SENSOR_VALUE, MAX_SENSOR_VALUE, MAX_SENSOR_VALUE }; 60 | uint16_t nextMedianDistance = 0; 61 | uint16_t minDistance = MAX_SENSOR_VALUE; 62 | uint16_t distance = MAX_SENSOR_VALUE; 63 | char* sensorLocation; 64 | // timestamp when the trigger signal was sent in us micros() 65 | uint32_t trigger = 0; 66 | volatile uint32_t start = 0; 67 | /* if end == 0 - a measurement is in progress */ 68 | volatile uint32_t end = 1; 69 | 70 | int32_t echoDurationMicroseconds[MAX_NUMBER_MEASUREMENTS_PER_INTERVAL + 1]; 71 | Median*median = nullptr; 72 | // statistics 73 | uint32_t maxDurationUs = 0; 74 | uint32_t minDurationUs = UINT32_MAX; 75 | uint32_t lastDelayTillStartUs = 0; 76 | // counts how often no echo and also no timeout signal was received 77 | // should only happen with defect or missing sensors 78 | uint32_t numberOfNoSignals = 0; 79 | uint32_t numberOfLowAfterMeasurement = 0; 80 | uint32_t numberOfToLongMeasurement = 0; 81 | uint32_t numberOfInterruptAdjustments = 0; 82 | uint16_t numberOfTriggers = 0; 83 | bool measurementRead; 84 | }; 85 | 86 | class HCSR04SensorManager { 87 | public: 88 | HCSR04SensorManager() {} 89 | virtual ~HCSR04SensorManager() {} 90 | void reset(uint32_t startMillisTicks); 91 | void registerSensor(const HCSR04SensorInfo &, uint8_t idx); 92 | void setOffsets(std::vector); 93 | void setPrimarySensor(uint8_t idx); 94 | void detachInterrupts(); 95 | void attachInterrupts(); 96 | /* Returns the current raw median distance in cm for the 97 | * given sensor. 98 | */ 99 | uint16_t getRawMedianDistance(uint8_t sensorId); 100 | /* Index for CSV. */ 101 | uint16_t getCurrentMeasureIndex(); 102 | uint32_t getMaxDurationUs(uint8_t sensorId); 103 | uint32_t getMinDurationUs(uint8_t sensorId); 104 | uint32_t getLastDelayTillStartUs(uint8_t sensorId); 105 | uint32_t getNoSignalReadings(const uint8_t sensorId); 106 | uint32_t getNumberOfLowAfterMeasurement(const uint8_t sensorId); 107 | uint32_t getNumberOfToLongMeasurement(const uint8_t sensorId); 108 | uint32_t getNumberOfInterruptAdjustments(const uint8_t sensorId); 109 | 110 | HCSR04SensorInfo m_sensors[NUMBER_OF_TOF_SENSORS]; 111 | uint16_t sensorValues[NUMBER_OF_TOF_SENSORS]; 112 | uint16_t lastReadingCount = 0; 113 | uint16_t startOffsetMilliseconds[MAX_NUMBER_MEASUREMENTS_PER_INTERVAL + 1]; 114 | bool pollDistancesParallel(); 115 | bool pollDistancesAlternating(); 116 | 117 | protected: 118 | 119 | private: 120 | void sendTriggerToSensor(uint8_t sensorId); 121 | bool collectSensorResult(uint8_t sensorId); 122 | void setSensorTriggersToLow(); 123 | bool collectSensorResults(); 124 | void attachSensorInterrupt(uint8_t idx); 125 | uint32_t getFixedStart(size_t idx, HCSR04SensorInfo * const sensor); 126 | boolean isReadyForStart(uint8_t sensorId); 127 | void registerReadings(); 128 | static uint16_t medianMeasure(HCSR04SensorInfo* const sensor, uint16_t value); 129 | static uint16_t median(uint16_t a, uint16_t b, uint16_t c); 130 | static uint16_t correctSensorOffset(uint16_t dist, uint16_t offset); 131 | static uint32_t microsBetween(uint32_t a, uint32_t b); 132 | static uint32_t microsSince(uint32_t a); 133 | static uint16_t millisSince(uint16_t milliseconds); 134 | static void updateStatistics(HCSR04SensorInfo * const sensor); 135 | uint32_t startReadingMilliseconds = 0; 136 | uint8_t primarySensor = 1; 137 | uint8_t lastSensor; 138 | }; 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /src/obsimprov.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OPENBIKESENSORFIRMWARE_OBSIMPROV_H 25 | #define OPENBIKESENSORFIRMWARE_OBSIMPROV_H 26 | 27 | /* TODO: 28 | * - provide short documentation (on index.html?) 29 | * - refactor as lib? 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | /** 37 | * Utility class to implement the improv protocol. 38 | * See protocol documentation at https://www.improv-wifi.com/serial/ for 39 | * the specification of the protocol. 40 | */ 41 | class ObsImprov { 42 | public: 43 | enum class State : uint8_t { 44 | READY = 0x02, 45 | PROVISIONING = 0x03, 46 | PROVISIONED = 0x04, 47 | }; 48 | 49 | /** 50 | * Create a new ObsImprov instance, able to handle incoming messages. 51 | * All callback methods must be expected to be called from "handle()" 52 | * call. 53 | * 54 | * @param initWifi callback method if new wifi data was received via improv. 55 | * must return true if a connection could be established. 56 | * @param getWifiStatus should return the status of the wifi connection. 57 | * @param getDeviceUrl if the device wifi is up the url needed to reach 58 | * the device should be returned, a empty string otherwise. 59 | */ 60 | ObsImprov(std::function initWifi, 61 | std::function getWifiStatus, 62 | std::function getDeviceUrl, 63 | HardwareSerial* serial = &Serial) : 64 | mSerial(serial), 65 | mInitWifi(initWifi), 66 | mWifiStatus(getWifiStatus), 67 | mDeviceUrl(getDeviceUrl) { }; 68 | 69 | /** 70 | * Check for new chars on serial. 71 | */ 72 | void handle(); 73 | 74 | /** 75 | * Consume given char as if it had been read from serial. 76 | * Can be used if there are several parties interested in serial data. 77 | * @param c the char to be consumed. 78 | */ 79 | void handle(char c); 80 | 81 | /** 82 | * Store detailed device information. 83 | * Should be called as soon as possible after creating a ObsImprov instance. 84 | * Empty data is reported upstream if needed earlier. 85 | */ 86 | void setDeviceInfo(const std::string & firmwareName, 87 | const std::string & firmwareVersion, 88 | const std::string & hardwareVariant, 89 | const std::string & deviceName); 90 | 91 | /** 92 | * Returns true if any improv message was received. 93 | * @return true if a improv message was received at any time 94 | */ 95 | bool isActive() const; 96 | 97 | private: 98 | enum class Type : uint8_t { 99 | CURRENT_STATE = 0x01, 100 | ERROR_STATE = 0x02, 101 | RPC_COMMAND = 0x03, 102 | RPC_RESULT = 0x04 103 | }; 104 | enum class Command : uint8_t { 105 | WIFI_SETTINGS = 0x01, 106 | GET_CURRENT_STATE = 0x02, 107 | GET_DEVICE_INFO = 0x03, 108 | GET_WIFI_NETWORKS = 0x04 109 | }; 110 | enum class Error : uint8_t { 111 | NOBE = 0x00, 112 | INVALID_RPC = 0x01, 113 | UNKNOWN_RPC = 0x02, 114 | UNABLE_TO_CONNECT = 0x03, 115 | UNKNOWN = 0xFF 116 | }; 117 | enum class Offset : uint8_t { 118 | TYPE = 0x00, 119 | LENGTH = 0x01, 120 | RPC_COMMAND = 0x02, 121 | RPC_DATA_LENGTH = 0x03, 122 | RPC_DATA_1 = 0x04 123 | }; 124 | HardwareSerial* mSerial; 125 | std::vector mBuffer; 126 | uint8_t mHeaderPos = 0; 127 | std::string mFirmwareName; 128 | std::string mFirmwareVersion; 129 | std::string mHardwareVariant; 130 | std::string mDeviceName; 131 | static const char *HEADER; 132 | static const uint8_t HEADER_LENGTH; 133 | const std::function mInitWifi; 134 | const std::function mWifiStatus; 135 | const std::function mDeviceUrl; 136 | bool mImprovActive = false; 137 | void sendWifiSuccess(Command cmd = Command::WIFI_SETTINGS) const; 138 | void sendCurrentState(State state) const; 139 | void sendErrorState(Error error) const; 140 | void handleRpcGetDeviceInfo() const; 141 | void appendStringAndLength(std::vector &response, std::string data) const; 142 | void sendPayload(Stream *stream, std::vector payload) const; 143 | bool isCompleteImprovMessage(std::vector buffer) const; 144 | bool isValidImprovMessage(std::vector buffer) const; 145 | void handleImprovMessage(std::vector buffer); 146 | void handleRpcWifiSettings(std::vector &buffer) const; 147 | void handleRpcGetCurrentState() const; 148 | void handleRpcGetWifiNetworks() const; 149 | void handleImprovBody(); 150 | }; 151 | 152 | 153 | #endif //OPENBIKESENSORFIRMWARE_OBSIMPROV_H 154 | -------------------------------------------------------------------------------- /src/utils/https.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "https.h" 25 | #include 26 | #include 27 | #include "esp_task_wdt.h" 28 | 29 | using namespace httpsserver; 30 | 31 | static volatile bool isCertReady = false; 32 | 33 | // "20190101000000" 34 | static std::string toCertDate(time_t theTime) { 35 | char date[32]; 36 | tm timeStruct; 37 | localtime_r(&theTime, &timeStruct); 38 | snprintf(date, sizeof(date), 39 | "%04d%02d%02d%02d%02d%02d", 40 | timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday, 41 | timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec); 42 | return std::string(date); 43 | } 44 | 45 | static std::string createDn() { 46 | char dn[128]; 47 | const uint64_t chipid_num = ESP.getEfuseMac(); 48 | // Placed the date in here - firefox does complain about duplicate cert 49 | // otherwise (we can not increase the serial number from here). 50 | snprintf(dn, sizeof(dn), 51 | "CN=obs.local,O=openbikesensor.org,OU=%04x%08x,L=%s,C=DE", 52 | (uint16_t)(chipid_num >> 32), 53 | (uint32_t)(chipid_num), 54 | toCertDate(time(nullptr)).c_str()); 55 | return std::string(dn); 56 | } 57 | 58 | static void createCert(void *param) { 59 | std::string fromDate; 60 | std::string toDate; 61 | time_t now = time(nullptr); 62 | if (now > (2020 - 1970) * 365 * 24 * 60 * 60) { 63 | fromDate = toCertDate(now); 64 | // Suggestion for hardware devices is to set the validity of the 65 | // cert to a high value. But Apple limits this value to 825 66 | // days in https://support.apple.com/HT210176 67 | toDate = toCertDate(now + 824 * 24 * 60 * 60); 68 | } else { 69 | fromDate = "20210513090700"; 70 | toDate = "20301231235959"; 71 | } 72 | 73 | log_i("DN will be %s", createDn().c_str()); 74 | 75 | SSLCert newCert; 76 | int res = createSelfSignedCert(newCert, 77 | KEYSIZE_2048, 78 | createDn(), 79 | fromDate, 80 | toDate); 81 | if (res != 0) { 82 | // Certificate generation failed. Inform the user. 83 | log_e("An error occurred during certificate generation."); 84 | log_e("Error code is 0x%04x", res); 85 | log_e("You may have a look at SSLCert.h to find the reason for this error."); 86 | } else { 87 | auto cert = static_cast(param); 88 | cert->setCert(newCert.getCertData(), newCert.getCertLength()); 89 | cert->setPK(newCert.getPKData(), newCert.getPKLength()); 90 | log_i("Created new cert."); 91 | } 92 | // Can this be done more elegant? 93 | isCertReady = true; 94 | vTaskDelete(nullptr); 95 | } 96 | 97 | bool Https::existsCertificate() { 98 | return SPIFFS.exists("/key.der") && SPIFFS.exists("/cert.der"); 99 | } 100 | 101 | /* Load or create cert. 102 | * Based on https://github.com/fhessel/esp32_https_server/blob/de1876cf6fe717cf236ad6603a97e88f22e38d62/examples/REST-API/REST-API.ino#L219 103 | * https://github.com/fhessel/esp32_https_server/issues/48 104 | */ 105 | SSLCert *Https::getCertificate(const std::function& progress) { 106 | // Try to open key and cert file to see if they exist 107 | File keyFile = SPIFFS.open("/key.der"); 108 | File certFile = SPIFFS.open("/cert.der"); 109 | 110 | // If now, create them 111 | if (!keyFile || !certFile || keyFile.size()==0 || certFile.size()==0) { 112 | log_i("No certificate found in SPIFFS, generating a new one."); 113 | log_i("This may take up to a minute, so please stand by :)"); 114 | 115 | auto newCert = new SSLCert(); 116 | xTaskCreate(reinterpret_cast(createCert), "createCert", 117 | 16 * 1024, newCert, 1, nullptr); 118 | 119 | while (!isCertReady) { 120 | if (progress) { 121 | progress(); 122 | } 123 | delay(100); 124 | esp_task_wdt_reset(); 125 | } 126 | 127 | bool failure = false; 128 | // Private key 129 | keyFile = SPIFFS.open("/key.der", FILE_WRITE); 130 | if (!keyFile || !keyFile.write(newCert->getPKData(), newCert->getPKLength())) { 131 | log_e("Could not write /key.der"); 132 | failure = true; 133 | } 134 | if (keyFile) keyFile.close(); 135 | 136 | // Certificate 137 | certFile = SPIFFS.open("/cert.der", FILE_WRITE); 138 | if (!certFile || !certFile.write(newCert->getCertData(), newCert->getCertLength())) { 139 | log_e("Could not write /cert.der"); 140 | failure = true; 141 | } 142 | if (certFile) certFile.close(); 143 | 144 | if (failure) { 145 | log_e("Certificate could not be stored permanently, generating new certificate on reboot..."); 146 | } 147 | return newCert; 148 | } else { 149 | log_i("Reading certificate from SPIFFS."); 150 | 151 | // The files exist, so we can create a certificate based on them 152 | size_t keySize = keyFile.size(); 153 | size_t certSize = certFile.size(); 154 | 155 | auto keyBuffer = new uint8_t[keySize]; 156 | if (keyBuffer == nullptr) { 157 | log_e("Not enough memory to load privat key"); 158 | return nullptr; 159 | } 160 | auto certBuffer = new uint8_t[certSize]; 161 | if (certBuffer == nullptr) { 162 | delete[] keyBuffer; 163 | log_e("Not enough memory to load certificate"); 164 | return nullptr; 165 | } 166 | keyFile.read(keyBuffer, keySize); 167 | certFile.read(certBuffer, certSize); 168 | 169 | keyFile.close(); 170 | certFile.close(); 171 | log_i("Read %u bytes of certificate and %u bytes of key from SPIFFS", certSize, keySize); 172 | return new SSLCert(certBuffer, certSize, keyBuffer, keySize); 173 | } 174 | } 175 | 176 | bool Https::removeCertificate() { 177 | SPIFFS.remove("/key.der"); 178 | SPIFFS.remove("/cert.der"); 179 | return !SPIFFS.exists("/key.der") && !SPIFFS.exists("/cert.der"); 180 | } 181 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_CONFIG_H 25 | #define OBS_CONFIG_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | enum DisplayOptions { 33 | DisplaySatellites = 0x01, // 1 34 | DisplayVelocity = 0x02, // 2 35 | DisplayLeft = 0x04, // 4 36 | DisplayRight = 0x08, // 8 37 | DisplaySimple = 0x10, // 16 38 | DisplaySwapSensors = 0x20, // 32 39 | DisplayInvert = 0x40, // 64 40 | DisplayFlip = 0x80, // 128 41 | DisplayNumConfirmed = 0x100, //256 42 | DisplayDistanceDetail = 0x200 // 512 43 | }; 44 | 45 | enum GPSOptions { 46 | ValidLocation = 0x01, //1 47 | ValidTime = 0x02, //2 48 | NumberSatellites = 0x04 //4 49 | }; 50 | 51 | enum PrivacyOptions { 52 | AbsolutePrivacy = 0x01, //1 53 | NoPosition = 0x02, //2 54 | NoPrivacy = 0x04, //4 55 | OverridePrivacy = 0x08 //8 56 | }; 57 | 58 | struct WifiConfig { 59 | String ssid = ""; 60 | String password = ""; 61 | bool trusted = false; 62 | }; 63 | 64 | struct PrivacyArea { 65 | double latitude; 66 | double longitude; 67 | double transformedLatitude; 68 | double transformedLongitude; 69 | double radius; 70 | }; 71 | 72 | // Most values should be moved away from here to the concrete implementation 73 | // which uses the value 74 | struct Config { 75 | char obsName[32]; 76 | std::vector sensorOffsets; 77 | char hostname[64]; 78 | char obsUserID[64]; 79 | uint displayConfig; 80 | bool bluetooth; 81 | int privacyConfig; 82 | int confirmationTimeWindow; 83 | std::vector privacyAreas; 84 | std::vector wifiConfigs; 85 | }; 86 | 87 | enum DevOptions { 88 | ShowGrid = 0x01, 89 | PrintWifiPassword = 0x02 90 | }; 91 | 92 | class ObsConfig { 93 | public: 94 | ObsConfig() : jsonData(4096) {}; 95 | ~ObsConfig() = default; 96 | bool loadConfig(); 97 | bool loadConfig(File &file); 98 | bool saveConfig() const; 99 | void printConfig() const; 100 | bool removeConfig(); 101 | 102 | std::vector getIntegersProperty(String const &name) const; 103 | template T getProperty(const String &key) const; 104 | bool setBitMaskProperty(int profile, const String &key, uint value, bool state); 105 | uint getBitMaskProperty(int profile, const String &key, uint mask) const; 106 | 107 | bool setProperty(int profile, const String &key, std::string const &value); 108 | bool setProperty(int profile, const String &key, String const &value); 109 | bool setProperty(int profile, const String &key, bool const &value); 110 | bool setProperty(int profile, const String &key, int const &value); 111 | template bool setProperty(int profile, const String &key, T const &value); 112 | bool setOffsets(int profile, std::vector const &value); 113 | 114 | bool setPrivacyArea(int profile, int paId, PrivacyArea const &pa); 115 | bool addPrivacyArea(int profile, PrivacyArea const &pa); 116 | bool removePrivacyArea(int profile, int paId); 117 | PrivacyArea getPrivacyArea(int profile, int paId) const; 118 | int getNumberOfPrivacyAreas(int profile) const; 119 | WifiConfig getWifiConfig(int wifiId) const; 120 | int getNumberOfWifiConfigs() const; 121 | bool removeWifiConfig(int wifiId); 122 | bool addWifiConfig(WifiConfig const &wifiConfig); 123 | bool setWifiConfig(int wifiId, WifiConfig const &wifiConfig); 124 | 125 | int getNumberOfProfiles() const; 126 | int addProfile(); 127 | bool deleteProfile(int profile); 128 | bool selectProfile(int profile); 129 | int getSelectedProfile() const; 130 | String getProfileName(int profile); // = getProperty(profile, "name") 131 | 132 | void fill(Config &cfg) const; 133 | /* free memory allocated by json document. */ 134 | void releaseJson(); 135 | String asJsonString() const; 136 | bool parseJson(const String &json); 137 | 138 | static const String PROPERTY_OBS_NAME; 139 | static const String PROPERTY_NAME; 140 | static const String PROPERTY_BLUETOOTH; 141 | static const String PROPERTY_OFFSET; 142 | static const String PROPERTY_SIM_RA; 143 | static const String PROPERTY_WIFI_SSID; 144 | static const String PROPERTY_WIFI_PASSWORD; 145 | static const String PROPERTY_WIFI_NETWORKS; 146 | static const String PROPERTY_WIFI_PRIVATE; 147 | static const String PROPERTY_PORTAL_TOKEN; 148 | static const String PROPERTY_PORTAL_URL; 149 | static const String PROPERTY_DISPLAY_CONFIG; 150 | static const String PROPERTY_CONFIRMATION_TIME_SECONDS; 151 | static const String PROPERTY_PRIVACY_CONFIG; 152 | static const String PROPERTY_SELECTED_PRESET; 153 | static const String PROPERTY_PRIVACY_AREA; 154 | static const String PROPERTY_PA_LAT; 155 | static const String PROPERTY_PA_LONG; 156 | static const String PROPERTY_PA_LAT_T; 157 | static const String PROPERTY_PA_LONG_T; 158 | static const String PROPERTY_PA_RADIUS; 159 | static const String PROPERTY_HTTP_PIN; 160 | 161 | private: 162 | static bool loadJson(JsonDocument &jsonDocument, const String &filename); 163 | static bool loadJson(JsonDocument &jsonDocument, fs::File &file); 164 | static bool parseJsonFromString(JsonDocument &jsonDocument, const String &jsonAsString); 165 | bool loadOldConfig(const String &filename); 166 | bool loadConfig(const String &filename); 167 | void parseOldJsonDocument(DynamicJsonDocument &document); 168 | void makeSureSystemDefaultsAreSet(); 169 | template bool ensureSet(JsonObject data, const String &key, T value); 170 | JsonObject getProfile(int profile); 171 | JsonObjectConst getProfileConst(int profile) const; 172 | void resetJson(); 173 | 174 | static const String CONFIG_OLD_FILENAME; 175 | static const String CONFIG_FILENAME; 176 | 177 | DynamicJsonDocument jsonData; 178 | int selectedProfile = 0; 179 | }; 180 | 181 | #endif 182 | -------------------------------------------------------------------------------- /src/utils/timeutils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "timeutils.h" 25 | 26 | #include 27 | #include 28 | 29 | 30 | /* Flag character used when time was set according to GPS Time */ 31 | static const char TIMEZONE_GPS = ' '; 32 | /* Flag character used when time was set according to UTC Time */ 33 | static const char TIMEZONE_UTC = 'Z'; 34 | /* Flag character used when time was not set */ 35 | static const char TIMEZONE_UNKNOWN = 'X'; 36 | 37 | // remember last timezone used, need to do it manually because GPS is not a 38 | // TimeZone in sense of linux supported time zones. 39 | static char timeZone = TIMEZONE_UNKNOWN; 40 | 41 | 42 | const uint32_t TimeUtils::SECONDS_PER_DAY = 60L * 60 * 24; 43 | const uint32_t TimeUtils::SECONDS_PER_WEEK = SECONDS_PER_DAY * 7; 44 | // use difftime() ? 45 | /* GPS Start time is 1980-01-06T00:00:00Z */ 46 | const uint32_t TimeUtils::GPS_EPOCH_OFFSET = 315964800L; 47 | 48 | 49 | const time_t TimeUtils::PAST_TIME = 30 * 365 * 24 * 60 * 60; 50 | const char *TimeUtils::WEEK_DAYS[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; 51 | const char *TimeUtils::MONTHS[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 52 | 53 | 54 | String TimeUtils::dateTimeToString(time_t timeIn) { 55 | char date[32]; 56 | time_t theTime; 57 | if (timeIn == 0) { 58 | theTime = time(nullptr); 59 | } else { 60 | theTime = timeIn; 61 | } 62 | tm timeStruct; 63 | localtime_r(&theTime, &timeStruct); 64 | snprintf(date, sizeof(date), 65 | "%04d-%02d-%02dT%02d:%02d:%02d", 66 | timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday, 67 | timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec); 68 | String result(date); 69 | if (timeIn == 0 && timeZone == TIMEZONE_UTC) { 70 | result += TIMEZONE_UTC; 71 | } 72 | return result; 73 | } 74 | 75 | String TimeUtils::timeToString(time_t timeIn) { 76 | char date[32]; 77 | time_t theTime; 78 | if (timeIn == 0) { 79 | theTime = time(nullptr); 80 | } else { 81 | theTime = timeIn; 82 | } 83 | if (theTime == 0) { 84 | theTime = time(nullptr); 85 | } 86 | tm timeStruct; 87 | localtime_r(&theTime, &timeStruct); 88 | snprintf(date, sizeof(date), 89 | "%02d:%02d:%02d", 90 | timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec); 91 | String result(date); 92 | if (timeIn == 0 && timeZone == TIMEZONE_UTC) { 93 | result += TIMEZONE_UTC; 94 | } 95 | return result; 96 | } 97 | 98 | String TimeUtils::dateTimeToHttpHeaderString(time_t theTime) { 99 | char date[32]; 100 | if (theTime == 0) { 101 | theTime = time(nullptr); 102 | } 103 | tm timeStruct; 104 | localtime_r(&theTime, &timeStruct); 105 | snprintf(date, sizeof(date), 106 | "%s, %02d %s %04d %02d:%02d:%02d GMT", 107 | weekDayToString(timeStruct.tm_wday), 108 | timeStruct.tm_mday, 109 | monthToString(timeStruct.tm_mon), 110 | timeStruct.tm_year + 1900, 111 | timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec); 112 | return String(date); 113 | } 114 | 115 | const char* TimeUtils::weekDayToString(uint8_t wDay) { 116 | if (wDay > 6) { 117 | return "???"; 118 | } else { 119 | return WEEK_DAYS[wDay]; 120 | } 121 | } 122 | 123 | const char* TimeUtils::monthToString(uint8_t mon) { 124 | if (mon > 11) { 125 | return "???"; 126 | } else { 127 | return MONTHS[mon]; 128 | } 129 | } 130 | 131 | void TimeUtils::setClockByNtp(const char* ntpServer) { 132 | if (!systemTimeIsSet()) { 133 | if (ntpServer) { 134 | log_d("Got additional NTP Server %s.", ntpServer); 135 | configTime( 136 | 0, 0, ntpServer, 137 | "rustime01.rus.uni-stuttgart.de", "pool.ntp.org"); 138 | } else { 139 | configTime( 140 | 0, 0, 141 | "rustime01.rus.uni-stuttgart.de", "pool.ntp.org"); 142 | } 143 | } 144 | timeZone = TIMEZONE_UTC; 145 | } 146 | 147 | void TimeUtils::setClockByGps(uint32_t iTow, int32_t fTow, int16_t week, int8_t leapS) { 148 | const time_t gpsTime = toTime(week, iTow / 1000); 149 | if (timeZone == TIMEZONE_UTC && systemTimeIsSet()) { 150 | log_i("Ignore new GPS time (%s), already set via NTP (%s).", 151 | dateTimeToString(gpsTime).c_str(), 152 | dateTimeToString().c_str()); 153 | return; 154 | } 155 | const int32_t gpsTimeUsec = ((iTow % 1000) * 1000) + (fTow / 1000); 156 | const struct timeval now = { 157 | .tv_sec = gpsTime, 158 | .tv_usec = gpsTimeUsec 159 | }; 160 | settimeofday(&now, nullptr); 161 | timeZone = TIMEZONE_GPS; 162 | } 163 | 164 | void TimeUtils::setClockByNtpAndWait(const char* ntpServer, uint32_t timeoutMs) { 165 | setClockByNtp(ntpServer); 166 | 167 | log_i("Waiting %dms for NTP time sync. ", timeoutMs); 168 | const uint32_t startMs = millis(); 169 | const uint32_t endMs = startMs + timeoutMs; 170 | while (!systemTimeIsSet() && (millis() < endMs)) { 171 | delay(100); 172 | } 173 | if (systemTimeIsSet()) { 174 | log_i("System time is set after %ums via NTP to %s.", millis() - startMs, dateTimeToString().c_str()); 175 | } else { 176 | log_e("System time could not be set via NTP after %ums starting with %s.", millis() - startMs, dateTimeToString().c_str()); 177 | } 178 | } 179 | 180 | bool TimeUtils::systemTimeIsSet() { 181 | time_t now = time(nullptr); 182 | log_v("time %s.", dateTimeToString(now).c_str()); 183 | return now > 1609681614; 184 | } 185 | 186 | /* Determine the number of leap seconds to be considered at the given GPS 187 | * time. 188 | * TODO: Make this more fancy leverage AID_HUI info that can be stored on 189 | * SD or hardcode dates if announced at 190 | * https://www.ietf.org/timezones/data/leap-seconds.list 191 | */ 192 | int16_t TimeUtils::getLeapSecondsGps(time_t gps) { 193 | return 18; 194 | } 195 | 196 | /* Determine the number of leap seconds to be considered at the given UTC 197 | * time. 198 | */ 199 | int16_t TimeUtils::getLeapSecondsUtc(time_t utc) { 200 | return 18; 201 | } 202 | 203 | time_t TimeUtils::gpsDayToTime(uint16_t week, uint16_t dayOfWeek) { 204 | return (time_t) GPS_EPOCH_OFFSET + (SECONDS_PER_WEEK * week) + (SECONDS_PER_DAY * dayOfWeek); 205 | } 206 | 207 | time_t TimeUtils::toTime(uint16_t week, uint32_t weekTime) { 208 | return (time_t) GPS_EPOCH_OFFSET + (SECONDS_PER_WEEK * week) + weekTime; 209 | } 210 | 211 | uint32_t TimeUtils::utcTimeToTimeOfWeek(time_t t) { 212 | return (t - GPS_EPOCH_OFFSET - getLeapSecondsGps(t)) % SECONDS_PER_WEEK; 213 | } 214 | 215 | uint16_t TimeUtils::utcTimeToWeekNumber(time_t t) { 216 | return (t - GPS_EPOCH_OFFSET - getLeapSecondsGps(t)) / SECONDS_PER_WEEK; 217 | } -------------------------------------------------------------------------------- /src/utils/alpdata.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include 25 | #include 26 | #include "globals.h" 27 | #include "alpdata.h" 28 | #include "timeutils.h" 29 | 30 | extern const uint8_t x509_crt_bundle_start[] asm("_binary_src_truststore_x509_crt_bundle_start"); 31 | 32 | /* Download http://alp.u-blox.com/current_14d.alp (ssl?) if there is a new one 33 | * Takes 5 seconds to update the data. 34 | */ 35 | void AlpData::update(DisplayDevice *display) { 36 | String lastModified = loadLastModified(); 37 | 38 | File f = SD.open(ALP_DATA_FILE_NAME, FILE_READ); 39 | const time_t lastWrite = f.getLastWrite(); 40 | if (!f || f.size() < ALP_DATA_MIN_FILE_SIZE ) { 41 | lastModified = ""; 42 | } else if (lastWrite > TimeUtils::PAST_TIME && 43 | time(nullptr) - lastWrite < 4 * 24 * 60 * 60) { 44 | log_d("File still current %s", 45 | TimeUtils::dateTimeToString(lastWrite).c_str()); 46 | log_d("Now: %s", 47 | TimeUtils::dateTimeToString(time(nullptr)).c_str()); 48 | log_d("Next Update: %s", 49 | TimeUtils::dateTimeToString(lastWrite + 4 * 24 * 60 * 60).c_str()); 50 | f.close(); 51 | display->showTextOnGrid(0, 5, "ALP not checked."); 52 | return; 53 | } 54 | f.close(); 55 | log_d("Existing file last write %s", TimeUtils::dateTimeToString(f.getLastWrite()).c_str()); 56 | log_d("Existing file is from %s", lastModified.c_str()); 57 | display->showTextOnGrid(0, 5, "ALP data..."); 58 | 59 | WiFiClientSecure wiFiClient; 60 | wiFiClient.setCACertBundle(x509_crt_bundle_start); 61 | HTTPClient httpClient; 62 | httpClient.begin(wiFiClient, ALP_DOWNLOAD_URL); 63 | const char *lastModifiedHeaderName = "Last-Modified"; 64 | const char *headers[] = {lastModifiedHeaderName}; 65 | httpClient.collectHeaders(headers, 1); 66 | // be polite - tell the server who we are 67 | httpClient.setUserAgent(String("openbikesensor.org/") + String(OBSVersion)); 68 | if (!lastModified.isEmpty()) { 69 | httpClient.addHeader("If-Modified-Since", lastModified); 70 | } 71 | int httpCode = httpClient.GET(); 72 | log_i("Size: %d", httpClient.getSize()); 73 | if (httpCode == 200) { 74 | String newLastModified = httpClient.header(lastModifiedHeaderName); 75 | File newFile = SD.open(ALP_NEW_DATA_FILE_NAME, FILE_WRITE); 76 | const int written = httpClient.writeToStream(&newFile); 77 | newFile.close(); 78 | log_e("Written: %d", written); 79 | if (written < ALP_DATA_MIN_FILE_SIZE) { 80 | displayHttpClientError(display, written); 81 | } else { 82 | log_e("Read %d bytes - all good! %s", written, newLastModified.c_str()); 83 | SD.remove(ALP_DATA_FILE_NAME); 84 | SD.rename(ALP_NEW_DATA_FILE_NAME, ALP_DATA_FILE_NAME); 85 | saveLastModified(newLastModified); 86 | display->showTextOnGrid(0, 5, "ALP data updated!"); 87 | } 88 | } else if (httpCode == 304) { // Not-Modified 89 | display->showTextOnGrid(0, 5, "ALP data was up to date."); 90 | log_i("All fine, not modified!"); 91 | } else if (httpCode > 0) { 92 | display->showTextOnGrid(0,4, String("ALP data failed ") + String(httpCode).c_str()); 93 | if (httpClient.getSize() < 200) { 94 | display->showTextOnGrid(0, 5, httpClient.getString().c_str()); 95 | } 96 | } else { 97 | displayHttpClientError(display, httpCode); 98 | } 99 | httpClient.end(); 100 | } 101 | 102 | void AlpData::displayHttpClientError(DisplayDevice *display, int httpError) { 103 | display->showTextOnGrid(0, 4, String("ALP data failed ") + String(httpError).c_str()); 104 | String errorString = HTTPClient::errorToString(httpError); 105 | display->showTextOnGrid(0, 5, errorString.c_str()); 106 | log_e("[HTTP] GET... failed, error %d: %s", httpError, errorString.c_str()); 107 | } 108 | 109 | bool AlpData::available() { 110 | return SD.exists(LAST_MODIFIED_HEADER_FILE_NAME); 111 | } 112 | 113 | void AlpData::saveLastModified(const String &header) { 114 | File f = SD.open(LAST_MODIFIED_HEADER_FILE_NAME, FILE_WRITE); 115 | if (f) { 116 | f.print(header); 117 | f.close(); 118 | } 119 | } 120 | 121 | String AlpData::loadLastModified() { 122 | File f = SD.open(LAST_MODIFIED_HEADER_FILE_NAME, FILE_READ); 123 | String lastModified = String(); 124 | if (f) { 125 | lastModified = f.readString(); 126 | } 127 | f.close(); 128 | return lastModified; 129 | } 130 | 131 | uint16_t AlpData::fill(uint8_t *data, size_t ofs, uint16_t dataSize) { 132 | if (!mAlpDataFile) { 133 | mAlpDataFile = SD.open(ALP_DATA_FILE_NAME, FILE_READ); 134 | } 135 | int read = -1; 136 | if (mAlpDataFile.seek(ofs)) { 137 | read = mAlpDataFile.read(data, dataSize); 138 | } 139 | if (read <= 0) { 140 | log_e("Failed to read got %d.", read); 141 | mAlpDataFile.close(); 142 | mAlpDataFile = SD.open(ALP_DATA_FILE_NAME, FILE_READ); 143 | if (mAlpDataFile.seek(ofs)) { 144 | read = mAlpDataFile.read(data, dataSize); 145 | } 146 | log_e("Read again: %d.", read); 147 | } 148 | // not closing the file saves 10ms per message 149 | // - need to take care when writing! 150 | return read; 151 | } 152 | 153 | /* Used to save AidIni data. */ 154 | void AlpData::saveMessage(const uint8_t *data, size_t size) { 155 | File f = SD.open(AID_INI_DATA_FILE_NAME, FILE_WRITE); 156 | if (f) { 157 | size_t written = f.write(data, size); 158 | f.close(); 159 | if (written != size) { 160 | log_e("Written only %d of %d bytes", written, size); 161 | } else { 162 | log_d("Written %d bytes", written); 163 | } 164 | } 165 | } 166 | 167 | /* Used to save AidIni data. */ 168 | size_t AlpData::loadMessage(uint8_t *data, size_t size) { 169 | size_t result = 0; 170 | File f = SD.open(AID_INI_DATA_FILE_NAME, FILE_READ); 171 | if (f) { 172 | result = f.read(data, size); 173 | f.close(); 174 | log_d("Read %d bytes", result); 175 | SD.remove(AID_INI_DATA_FILE_NAME); 176 | } 177 | return result; 178 | } 179 | 180 | void AlpData::save(const uint8_t *data, size_t offset, int length) { 181 | #ifdef RANDOM_ACCESS_FILE_AVAILAVLE 182 | // this is currently not possible to seek and modify data within an existing 183 | // file, we can only append :( 184 | if (!mAlpDataFile) { 185 | mAlpDataFile = SD.open(ALP_DATA_FILE_NAME, FILE_APPEND); 186 | } 187 | int written = -99; 188 | if (mAlpDataFile.seek(offset)) { 189 | written = mAlpDataFile.write(data, length); 190 | } 191 | if (written <= 0) { 192 | log_e("Failed to write got %d.", written); 193 | mAlpDataFile.close(); 194 | mAlpDataFile = SD.open(ALP_DATA_FILE_NAME, FILE_APPEND); 195 | if (mAlpDataFile.seek(offset)) { 196 | written = mAlpDataFile.write(data, length); 197 | } 198 | log_e("Write again: %d.", written); 199 | } 200 | #endif 201 | } 202 | -------------------------------------------------------------------------------- /src/Firmware.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | #include "Arduino.h" 24 | #include "Firmware.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | // https://docs.platformio.org/en/latest/platforms/espressif32.html#embedding-binary-data 32 | extern const uint8_t x509_crt_bundle_start[] asm("_binary_src_truststore_x509_crt_bundle_start"); 33 | 34 | static const String FLASH_APP_FILENAME("/sdflash/app.bin"); 35 | static const String OPEN_BIKE_SENSOR_FLASH_APP_PROJECT_NAME("OpenBikeSensorFlash"); 36 | static const size_t APP_PARTITION_SIZE = 0x380000; // read from part? 37 | static const int SHA256_HASH_LEN = 32; 38 | 39 | // todo: error handling 40 | void Firmware::downloadToSd(String url, String filename, bool unsafe) { 41 | WiFiClientSecure client; 42 | if (!unsafe) client.setCACertBundle(x509_crt_bundle_start); 43 | else client.setInsecure(); 44 | HTTPClient http; 45 | http.setUserAgent(mUserAgent); 46 | http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); 47 | 48 | if (http.begin(client, url)) { 49 | int status = http.GET(); 50 | log_i("Opening %s got %d.", url.c_str(), status); 51 | log_i("http size: %d. ", http.getSize()); 52 | log_i("Will access Stream:, free heap %dkb", ESP.getFreeHeap() / 1024); 53 | if (status == 200) { 54 | File newFile = SD.open(filename, FILE_WRITE); 55 | int written = http.writeToStream(&newFile); 56 | newFile.close(); 57 | log_i("Got %d bytes", written); 58 | } 59 | } 60 | http.end(); 61 | } 62 | 63 | bool Firmware::downloadToFlash(String url, 64 | std::function progress, 65 | bool unsafe) { 66 | bool success = false; 67 | WiFiClientSecure client; 68 | if (!unsafe) client.setCACertBundle(x509_crt_bundle_start); 69 | else client.setInsecure(); 70 | HTTPClient http; 71 | http.setUserAgent(mUserAgent); 72 | http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); 73 | if (http.begin(client, url)) { 74 | progress(0, 999); 75 | int status = http.GET(); 76 | log_i("Opening %s got %d.", url.c_str(), status); 77 | size_t size = http.getSize(); 78 | log_i("http size: %d. ", size); 79 | log_i("Will access Stream:, free heap %dkb", ESP.getFreeHeap() / 1024); 80 | if (status == HTTP_CODE_OK) { 81 | Update.begin(); 82 | Update.onProgress([progress, size](size_t pos, size_t all) { 83 | progress(pos, size); 84 | }); 85 | 86 | Stream& stream = http.getStream(); 87 | byte buffer[256]; 88 | size_t read; 89 | size_t written = 0; 90 | while ((read = stream.readBytes(&buffer[0], sizeof(buffer))) > 0) { 91 | Update.write(buffer, read); 92 | written += read; 93 | } 94 | log_i("Got %d bytes", written); 95 | } else { 96 | log_e("Got http status: %d", status); 97 | http.end(); 98 | return false; 99 | } 100 | } 101 | http.end(); 102 | if (Update.end(true)) { //true to set the size to the current progress 103 | mLastMessage = "Success"; 104 | 105 | // Suppress the ota Firmware switch! 106 | const esp_partition_t *running = esp_ota_get_running_partition(); 107 | esp_ota_set_boot_partition(running); 108 | success = true; 109 | } else { 110 | mLastMessage = Update.errorString(); 111 | log_e("Update: %s", mLastMessage.c_str()); 112 | } 113 | return success; 114 | } 115 | 116 | String Firmware::getLastMessage() { 117 | return mLastMessage; 118 | }; 119 | 120 | const esp_partition_t* Firmware::findEspFlashAppPartition() { 121 | const esp_partition_t *part 122 | = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, nullptr); 123 | 124 | esp_app_desc_t app_desc; 125 | esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc)); 126 | 127 | if (ret != ESP_OK || OPEN_BIKE_SENSOR_FLASH_APP_PROJECT_NAME != app_desc.project_name) { 128 | part 129 | = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, 130 | nullptr); 131 | ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc)); 132 | } 133 | 134 | if (ret == ESP_OK && OPEN_BIKE_SENSOR_FLASH_APP_PROJECT_NAME == app_desc.project_name) { 135 | return part; 136 | } else { 137 | return nullptr; 138 | } 139 | } 140 | 141 | String Firmware::getFlashAppVersion() { 142 | const esp_partition_t *part = findEspFlashAppPartition(); 143 | esp_app_desc_t app_desc; 144 | esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc)); 145 | String version; 146 | if (ret == ESP_OK) { 147 | version = app_desc.version; 148 | } 149 | return version; 150 | } 151 | 152 | static void calculateSha256(File &f, uint8_t *shaResult, int32_t bytes) { 153 | mbedtls_md_context_t ctx; 154 | mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; 155 | mbedtls_md_init(&ctx); 156 | mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0); 157 | mbedtls_md_starts(&ctx); 158 | 159 | const uint16_t bufferSize = 8192; 160 | uint8_t *buffer = static_cast(malloc(bufferSize)); 161 | uint32_t toRead = bufferSize; 162 | uint32_t read; 163 | uint32_t readFromFile = 0; 164 | while ((read = f.read(buffer, toRead)) > 0) { 165 | mbedtls_md_update(&ctx, buffer, read); 166 | readFromFile += read; 167 | if (readFromFile + toRead > bytes) { 168 | toRead = bytes - readFromFile; 169 | } 170 | } 171 | free(buffer); 172 | mbedtls_md_finish(&ctx, shaResult); 173 | mbedtls_md_free(&ctx); 174 | } 175 | 176 | String Firmware::checkSdFirmware() { 177 | String error; 178 | File f = SD.open(FLASH_APP_FILENAME, FILE_READ); 179 | if (!f) { 180 | error = "Failed to find '" + FLASH_APP_FILENAME + "' on sd card."; 181 | return error; 182 | } 183 | const int32_t fileSize = f.size(); 184 | if (fileSize > APP_PARTITION_SIZE) { 185 | error = "Firmware to flash is to large. "; 186 | } else { 187 | uint8_t shaResult[SHA256_HASH_LEN]; 188 | calculateSha256(f, shaResult, fileSize - SHA256_HASH_LEN); 189 | 190 | for (int i = 0; i < SHA256_HASH_LEN; i++) { 191 | int c = f.read(); 192 | if (shaResult[i] != c) { 193 | error = "Checksum mismatch."; 194 | break; 195 | } 196 | } 197 | } 198 | f.close(); 199 | return error; 200 | } 201 | 202 | bool Firmware::switchToFlashApp() { 203 | bool success = false; 204 | const esp_partition_t *part = findEspFlashAppPartition(); 205 | if (part) { 206 | success = (ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_set_boot_partition(part)) == ESP_OK); 207 | } 208 | return success; 209 | } 210 | -------------------------------------------------------------------------------- /docs/software/firmware/csv_format.md: -------------------------------------------------------------------------------- 1 | # Format specification for the internal CSV format 2 | 3 | ## Encoding 4 | 5 | The whole data file is encoded as UTF-8. Writers of the file may choose not to use the whole unicode range for simplicity and restrict themselves to 7-bit ASCII for simplicity, because it is identical with UTF-8. The OBS does this for example, since it only produces data that can be encoded this way. Parsers should interpret the whole file as UTF-8 however, since other data sources may produce special characters inside the file, such as in free text comment fields. 6 | 7 | The file must not include a [BOM](https://de.wikipedia.org/wiki/Byte_Order_Mark). 8 | 9 | ## Metadata 10 | 11 | The 1st line of the CSV file contains key value metadata as URL encoded 12 | parameters. This line must be skipped to get a full CVS conform format. 13 | A sample line could look like follows: 14 | 15 | ```URL 16 | OBSFirmwareVersion=v0.3.999&OBSDataFormat=2&DataPerMeasurement=3&\ 17 | MaximumMeasurementsPerLine=60&OffsetLeft=30&OffsetRight=30&\ 18 | NumberOfDefinedPrivacyAreas=3&PrivacyLevelApplied=AbsolutePrivacy&\ 19 | MaximumValidFlightTimeMicroseconds=18560&\ 20 | DistanceSensorsUsed=HC-SR04/JSN-SR04T&DeviceId=ecec 21 | ``` 22 | 23 | There might be new keys added. Parsers should ignore values they do not 24 | understand. 25 | 26 | | Key | Example value | Note | 27 | | --- | ------------- | ---- | 28 | | `OBSDataFormatVersion` | `2` | **Required**. This the version of this format specification that the file follows. | 29 | | `OBSFirmwareVersion` | `v0.3.999` | | 30 | | `DataPerMeasurement` | `3` | fix as of now is `Tms`, `Lus` and `Rus` | 31 | | `MaximumMeasurementsPerLine` | `60` | currently fix | 32 | | `HandlebarOffsetLeft` | `30` | as set in the configurations | 33 | | `HandlebarOffsetRight` | `30` | as set in the configurations | 34 | | `NumberOfDefinedPrivacyAreas` | `3` | as set in the configuration, just to be aware of | 35 | | `PrivacyLevelApplied` | `AbsolutePrivacy` | One of: NoPrivacy, NoPosition, OverridePrivacy, AbsolutePrivacy | 36 | | `MaximumValidFlightTimeMicroseconds` | `18560` | all echo times above this value must be discarded and treated as no object in sight | 37 | | `DistanceSensorsUsed` | `HC-SR04/JSN-SR04T` | enum currently only one possible value | 38 | | `DeviceId` | `affe` | internal Id of the OBS | 39 | | `PresetId` | `Wade` | Id to identify the selected preset. A owner might define multiple presets | 40 | | `BluetoothEnabled` | `1` | 1 if bluetooth is enabled, 0 otherwise 41 | | `TrackId` | `38605ba-76...` | A uuid that can be used to uniquely identify the track. 42 | | `TimeZone` | `GPS` | The time zone used to write Date and Time data. Typically this is GPS which is some leap seconds ahead of UTC (as of today 18). UTC is also a allowed value and the default if not TimeZone is given. 43 | 44 | ## CSV 45 | 46 | As 2nd line, the file contains a header line with headline entries for 47 | each field, the names must be the same as given in the table below. 48 | The number of data entries per line can differ. 49 | 50 | If there is no value in an entry this means no measurement or not 51 | available or hidden. Before we used `-1` or `NaN` for this, now we are 52 | less polite and save the space. 53 | 54 | There is typically one line per second, but there are possible exceptions: 55 | - Timing might be bad, and we miss one second, use the `Millis` field if 56 | you need more precise timings. 57 | - If we have multiple confirmed measurements in one interval in that case 58 | an interval appears multiple times - once with each confirmed value. 59 | Other fields are identical in both lines. 60 | 61 | The header defines the order of the fields, it can be different from 62 | the order here. Also fields that do not appear in the header must be 63 | assumed empty for the whole file. 64 | 65 | 66 | NOTE: The order of the fields is different from Version 1 of the CVS file. 67 | 68 | ### CSV-DIALECT 69 | 70 | Based on http://dataprotocols.org/csv-dialect/ the definition is: 71 | 72 | ```json 73 | { 74 | "csvddfVersion": 1.2, 75 | "delimiter": ";", 76 | "lineTerminator": "\n", 77 | "skipInitialSpace": true, 78 | "header": true 79 | } 80 | ``` 81 | 82 | ### Data 83 | 84 | Headline | Format | Range | Sample | Description | 85 | --- | --- | --- | --- | --- | 86 | `Date` | TT.MM.YYYY | | 24.11.2020 | Time, typically as received by the GPS module. If there was no reception of a time signal yet, this might be unix time (starting 1.1.1970) which can be used as offset between the csv lines. Expect none linearity when time is set. 87 | `Time` | HH:MM:SS | | 12:00:00 | TimeZone is GPS or UTC according to the TimeZone metadata. 88 | `Millis` | int32 | 0-2^31 | 1234567 | Millisecond counter will continuously increase throughout the file, for time difference calculation 89 | `Comment` | char[] | | | Space to leave a short text comment 90 | `Latitude` | double | -90.0-90.0 | 42.123456 | Latitude as degrees 91 | `Longitude` | double | -180.0-180.0 | 9.123456 | Longitude in degrees 92 | `Altitude` | double | -9999.9-17999.9 | 480.12 | meters above mean sea level (GPGGA) 93 | `Course` | double | 0-359.9 | 42 | Course over ground in degrees (GPRMC) 94 | `Speed` | double | 0-359.9 | 42.0 | Speed over ground in km/h 95 | `HDOP` | double | 0-99.9 | 2.3 | Relative accuracy of horizontal position (GPGGA) 96 | `Satellites` | int16 | 0-99 | 5 | Number of satellites in use (GPGGA) 97 | `BatteryLevel` | double | 0-9.99 | 3.3 | Current battery level reading (~V) 98 | `Left` | int16 | 0-999 | 150 | Left minimum measured distance in centimeters of this line, the measurement is already corrected for the handlebar offset. 99 | `Right` | int16 | 0-999 | 150 | Right minimum measured distance as `Left` above. 100 | `Confirmed` | int32 | 0-60 | 5 | If !=0 the Measurement was confirmed overtaking by button press, contains the index `` of the related measurement 101 | `Marked` | char[] | | "OVERTAKING" | Measurement was marked (not possible yet) with the given tag use | to separate multiple tags is needed. 102 | `Invalid` | int16 | 0-1 | 1 | Measurement was marked as invalid reading (not possible yet) 103 | `InsidePrivacyArea`| int16 | 0-1 | 1 | 104 | `Factor` | double | | 58 | The factor used to calculate the time given in micro seconds (us) into centimeters (cm). Currently fix, might get adjusted by temperature some time later. | 105 | `Measurements` | int16 | 0-999 | 18 | Number of measurements entries in this line | 106 | _comment_ | | | | Now follows a series of #`Measurements` repetitions of #`DatasPerMeasurement` entries, `` is always increased starting from 1 for the 1st measurement. Order is always the same, additional data might be added to the end, `DatasPerMeasurement` will be increased then. | 107 | `Tms` | int16 | 0-1999 | 234 | Millisecond (ms) offset of measurement in this series (line) of measurements | 108 | `Lus` | int32 | 0-100000 | 3456 | Microseconds (us) till the echo was received by the left sensor, divide by the `Factor` given above to get the distance in centimeters you might also want to apply the handlebar offset given in the metadata. Empty for no measurement taken. Values above `MaximumValidFlightTimeMicroseconds` (metadata) point to a measurement timeout when there is no object in sight.| 109 | `Rus` | int32 | 0-100000 | 3456 | As `Lus` above for the right sensor. | 110 | 111 | 112 | Possible Header: 113 | 114 | ```csv 115 | Date;Time;Millis;Latitude;Longitude;Altitude; \ 116 | Course;Speed;HDOP;Satellites;BatteryLevel;Left;Right;Confirmed;Marked;Invalid; \ 117 | insidePrivacyArea;Factor;Measurements;Tms1;Lus1;Rus1;Tms2;Lus2;Rus2; \ 118 | Tms3;Lus3;Rus3;...;Tms60;Lus60;Rus60 119 | ``` 120 | -------------------------------------------------------------------------------- /src/logo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #ifndef OBS_LOGO_H 25 | #define OBS_LOGO_H 26 | 27 | #include 28 | 29 | #define OBSLogo_width 128 30 | #define OBSLogo_height 64 31 | const unsigned char OBSLogo [] PROGMEM = { 32 | // 'OBS Logo S, 128x64px 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xfc, 0xfc, 0x8d, 0x03, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 44 | 0xfc, 0xfd, 0x9d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x80, 0x03, 0x00, 0xee, 0xfc, 0xfd, 0x9d, 0x03, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc6, 0x8c, 0x1d, 0x9c, 0x03, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc7, 48 | 0x8c, 0x1d, 0xbc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x80, 0xff, 0x3f, 0xc7, 0x8c, 0xfd, 0xbc, 0x03, 0x00, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x3f, 0xc7, 0xcc, 0xfd, 0xfc, 0x03, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x3f, 0xc7, 52 | 0xfc, 0xfd, 0xec, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x80, 0x03, 0x00, 0xc7, 0xfc, 0x1c, 0xec, 0x03, 0x00, 0x00, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc7, 0x3c, 0x1c, 0xec, 0x03, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc6, 56 | 0x0c, 0x1c, 0xcc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x80, 0x03, 0x00, 0xe6, 0x0c, 0x1c, 0xcc, 0x03, 0x00, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0c, 0xfc, 0x8d, 0x03, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 60 | 0x0c, 0xfc, 0x8d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x38, 0x0c, 0xfc, 0x0d, 0x03, 0x00, 0x00, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0x80, 0x07, 0x33, 0xc6, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x33, 0xe6, 0x0f, 0x00, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x33, 0xe7, 68 | 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 | 0x80, 0x39, 0x33, 0xe3, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 70 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x31, 0xb3, 0xe3, 0x00, 0x00, 0x80, 0x03, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x39, 0xf3, 0xe1, 72 | 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 | 0x80, 0x3f, 0xf3, 0xe1, 0xe7, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 74 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0xf3, 0xe1, 0xe7, 0xff, 0xff, 0x03, 75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0xf3, 0xe3, 76 | 0xe7, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 | 0x80, 0x39, 0xf3, 0xe3, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 78 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x31, 0x73, 0xe3, 0x00, 0x00, 0x80, 0x03, 79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x31, 0x33, 0xe7, 80 | 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x80, 0x39, 0x33, 0xe7, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x33, 0xee, 0x0f, 0x00, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x33, 0xee, 84 | 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 | 0x80, 0x07, 0x33, 0xcc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 | 0x00, 0x8f, 0x9f, 0x31, 0x3c, 0x38, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x9f, 0x71, 0x7e, 0x7c, 0xfc, 0x00, 91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf, 0x9f, 0x73, 92 | 0x7f, 0xfe, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93 | 0x80, 0x99, 0x83, 0x73, 0x27, 0xe6, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0x81, 0x73, 0x03, 0xc7, 0x8c, 0x01, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0x81, 0x77, 96 | 0x07, 0xc7, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 97 | 0x80, 0x87, 0x9f, 0x77, 0x1f, 0xc7, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 98 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x9f, 0x7f, 0x3e, 0xc7, 0xfc, 0x01, 99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x9f, 0x7d, 100 | 0x7c, 0xc7, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 101 | 0x00, 0xbc, 0x81, 0x7d, 0x78, 0xc7, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x81, 0x7d, 0x60, 0xc7, 0xcc, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x81, 0x79, 104 | 0x62, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 | 0x80, 0xb9, 0x9f, 0x79, 0x77, 0xee, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 106 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x9f, 0x71, 0x7f, 0x7e, 0xcc, 0x01, 107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x9f, 0x71, 108 | 0x3e, 0x7c, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 109 | 0x00, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 114 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 115 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 116 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 118 | 0x00, 0x00, 0x00, 0x00 119 | }; 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /src/displays.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019-2021 OpenBikeSensor Contributors 3 | * Contact: https://openbikesensor.org 4 | * 5 | * This file is part of the OpenBikeSensor firmware. 6 | * 7 | * The OpenBikeSensor firmware is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * Lesser General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your option) 11 | * any later version. 12 | * 13 | * OpenBikeSensor firmware is distributed in the hope that 14 | * it will be useful, but WITHOUT ANY WARRANTY; without even the 15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | * PURPOSE. See the GNU Lesser General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with the OpenBikeSensor firmware. If not, 21 | * see . 22 | */ 23 | 24 | #include "displays.h" 25 | 26 | #include "fonts/logos.h" 27 | 28 | void DisplayDevice::showNumConfirmed() { 29 | String val = String(confirmedMeasurements); 30 | if (confirmedMeasurements <= 9) { 31 | val = "0" + val; 32 | } 33 | this->prepareTextOnGrid(2, 4, val, MEDIUM_FONT); 34 | this->prepareTextOnGrid(3, 5, "conf"); 35 | } 36 | 37 | void DisplayDevice::showNumButtonPressed() { 38 | String val = String(numButtonReleased); 39 | if (numButtonReleased <= 9) { 40 | val = "0" + val; 41 | } 42 | this->prepareTextOnGrid(0, 4, val, MEDIUM_FONT); 43 | this->prepareTextOnGrid(1, 5, "press"); 44 | } 45 | 46 | void DisplayDevice::displaySimple(uint16_t value) { 47 | if (value == MAX_SENSOR_VALUE) { 48 | this->prepareTextOnGrid(0, 0, 49 | "", HUGE_FONT, -7, 0); 50 | } else { 51 | this->prepareTextOnGrid(0, 0, 52 | ObsUtils::to3DigitString(value), HUGE_FONT, -7, 0); 53 | } 54 | this->prepareTextOnGrid(3, 2, "cm", MEDIUM_FONT, -7, -5); 55 | } 56 | 57 | void DisplayDevice::showValues( 58 | uint16_t sensor1MinDistance, const char* sensor1Location, uint16_t sensor1RawDistance, 59 | uint16_t sensor2MinDistance, const char* sensor2Location, uint16_t sensor2RawDistance, uint16_t sensor2Distance, 60 | uint16_t minDistanceToConfirm, int16_t batteryPercentage, 61 | int16_t TemperaturValue, int lastMeasurements, boolean insidePrivacyArea, 62 | double speed, uint8_t satellites) { 63 | 64 | handleHighlight(); 65 | 66 | uint16_t value1 = sensor1MinDistance; 67 | if (minDistanceToConfirm != MAX_SENSOR_VALUE) { 68 | value1 = minDistanceToConfirm; 69 | } 70 | if (config.displayConfig & DisplaySimple) { 71 | displaySimple(value1); 72 | } else { 73 | if (config.displayConfig & DisplayLeft) { 74 | String loc1 = sensor1Location; 75 | if (insidePrivacyArea) { 76 | loc1 = "(" + loc1 + ")"; 77 | } 78 | this->prepareTextOnGrid(0, 0, loc1); 79 | if (value1 == MAX_SENSOR_VALUE) { 80 | this->prepareTextOnGrid(0, 1, "---", LARGE_FONT); 81 | } else { 82 | this->prepareTextOnGrid(0, 1, 83 | ObsUtils::to3DigitString(value1), LARGE_FONT); 84 | } 85 | } 86 | // Show sensor2, when DisplayRight is configured 87 | if (config.displayConfig & DisplayRight) { 88 | uint16_t value2 = sensor2Distance; 89 | String loc2 = sensor2Location; 90 | this->prepareTextOnGrid(3, 0, loc2); 91 | if (value2 == MAX_SENSOR_VALUE || value2 == 0) { 92 | this->prepareTextOnGrid(2, 1, "---", LARGE_FONT, 5, 0); 93 | } else { 94 | this->prepareTextOnGrid(2, 1, 95 | ObsUtils::to3DigitString(value2), LARGE_FONT, 5, 0); 96 | } 97 | } 98 | } // NOT SIMPLE 99 | if (config.displayConfig & DisplayDistanceDetail) { 100 | const int bufSize = 64; 101 | char buffer[bufSize]; 102 | // #ifdef NERD_SENSOR_DISTANCE 103 | snprintf(buffer, bufSize - 1, "%03d|%02d|%03d", sensor1RawDistance, 104 | lastMeasurements, sensor2RawDistance); 105 | // #endif 106 | #ifdef NERD_HEAP 107 | snprintf(buffer, bufSize - 1, "%03d|%02d|%uk", sensor1RawDistance, 108 | lastMeasurements, ESP.getFreeHeap() / 1024); 109 | #endif 110 | #ifdef NERD_VOLT 111 | snprintf(buffer, bufSize - 1, "%03d|%02d|%3.2fV", sensor1RawDistance, 112 | lastMeasurements, voltageMeter->read()); 113 | #endif 114 | #ifdef NERD_GPS 115 | snprintf(buffer, bufSize - 1, "%02ds|%s|%03u", 116 | satellites, 117 | gps.getHdopAsString().c_str(), gps.getLastNoiseLevel() ); 118 | #endif 119 | this->prepareTextOnGrid(0, 4, buffer, MEDIUM_FONT); 120 | } else if (config.displayConfig & DisplayNumConfirmed) { 121 | showNumButtonPressed(); 122 | showNumConfirmed(); 123 | } else { 124 | // Show GPS info, when DisplaySatellites is configured 125 | if (config.displayConfig & DisplaySatellites) { 126 | showGPS(satellites); 127 | } 128 | 129 | // Show velocity, when DisplayVelocity is configured 130 | if (config.displayConfig & DisplayVelocity) { 131 | showSpeed(speed); 132 | } 133 | } 134 | if (batteryPercentage >= -1) { 135 | showBatterieValue(batteryPercentage); 136 | } 137 | if (!(config.displayConfig & DisplaySimple)){ 138 | if(BMP280_active == true) 139 | showTemperatureValue(TemperaturValue); 140 | } 141 | 142 | m_display->updateDisplay(); 143 | 144 | } 145 | 146 | void DisplayDevice::showGPS(uint8_t sats) { 147 | String val = String(sats); 148 | if (sats <= 9) { 149 | val = "0" + val; 150 | } 151 | this->prepareTextOnGrid(2, 4, val, MEDIUM_FONT); 152 | this->prepareTextOnGrid(3, 5, "sats"); 153 | } 154 | 155 | void DisplayDevice::showBatterieValue(int16_t input_val){ 156 | 157 | uint8_t x_offset_batterie_logo = 65; 158 | uint8_t y_offset_batterie_logo = 2; 159 | int8_t xlocation = 2; 160 | 161 | if ((config.displayConfig & DisplaySimple)){ 162 | x_offset_batterie_logo += 32; 163 | xlocation += 1; 164 | } 165 | 166 | if(input_val >= 0){ 167 | String val = String(input_val); 168 | //showLogo(true); 169 | this->showTextOnGrid(xlocation, 0, val + "%", TINY_FONT, 6, 0); 170 | 171 | if(input_val > 90){ 172 | cleanBattery(x_offset_batterie_logo, y_offset_batterie_logo); 173 | m_display->drawXBM(x_offset_batterie_logo, y_offset_batterie_logo, 8, 9, BatterieLogo1); 174 | }else if (input_val > 70) 175 | { 176 | cleanBattery(x_offset_batterie_logo, y_offset_batterie_logo); 177 | m_display->drawXBM(x_offset_batterie_logo, y_offset_batterie_logo, 8, 9, BatterieLogo2); 178 | }else if (input_val> 50) 179 | { 180 | cleanBattery(x_offset_batterie_logo, y_offset_batterie_logo); 181 | m_display->drawXBM(x_offset_batterie_logo, y_offset_batterie_logo, 8, 9, BatterieLogo3); 182 | }else if (input_val > 30) 183 | { 184 | cleanBattery(x_offset_batterie_logo, y_offset_batterie_logo); 185 | m_display->drawXBM(x_offset_batterie_logo, y_offset_batterie_logo, 8, 9, BatterieLogo4); 186 | }else if (input_val >10) 187 | { 188 | cleanBattery(x_offset_batterie_logo, y_offset_batterie_logo); 189 | m_display->drawXBM(x_offset_batterie_logo, y_offset_batterie_logo, 8, 9, BatterieLogo5); 190 | }else 191 | { 192 | cleanBattery(x_offset_batterie_logo, y_offset_batterie_logo); 193 | m_display->drawXBM(x_offset_batterie_logo, y_offset_batterie_logo, 8, 9, BatterieLogo6); 194 | } 195 | 196 | } 197 | } 198 | 199 | void DisplayDevice::showTemperatureValue(int16_t input_val){ 200 | uint8_t x_offset_temp_logo = 30; 201 | uint8_t y_offset_temp_logo = 2; 202 | cleanTemperatur(x_offset_temp_logo,y_offset_temp_logo); 203 | m_display->drawXBM(x_offset_temp_logo, y_offset_temp_logo, 8, 9, TempLogo); 204 | String val = String(input_val); 205 | this->showTextOnGrid(1, 0, val + "°C", TINY_FONT); 206 | } 207 | 208 | void DisplayDevice::showSpeed(double velocity) { 209 | const int bufSize = 4; 210 | char buffer[bufSize]; 211 | if (velocity >= 0) { 212 | snprintf(buffer, bufSize - 1, "%02d", (int) velocity); 213 | } else { 214 | snprintf(buffer, bufSize - 1, "--"); 215 | } 216 | this->prepareTextOnGrid(0, 4, buffer, MEDIUM_FONT); 217 | this->prepareTextOnGrid(1, 5, "km/h"); 218 | } 219 | 220 | uint8_t DisplayDevice::currentLine() const { 221 | return mCurrentLine; 222 | } 223 | 224 | uint8_t DisplayDevice::newLine() { 225 | if (mCurrentLine >= 5) { 226 | scrollUp(); 227 | } 228 | return ++mCurrentLine; 229 | } 230 | 231 | uint8_t DisplayDevice::scrollUp() { 232 | for (uint8_t i = 0; i < 5; i++) { 233 | prepareTextOnGrid(2, i, obsDisplay->get_gridTextofCell(2, i + 1)); 234 | } 235 | m_display->updateDisplay(); 236 | return mCurrentLine--; 237 | } 238 | 239 | uint8_t DisplayDevice::startLine() { 240 | return mCurrentLine = 0; 241 | } 242 | 243 | void DisplayDevice::highlight(uint32_t highlightTimeMillis) { 244 | mHighlightTill = millis() + highlightTimeMillis; 245 | if (!mHighlighted) { 246 | setInversion(!mInverted); 247 | mHighlighted = true; 248 | } 249 | } 250 | 251 | void DisplayDevice::handleHighlight() { 252 | if (mHighlighted && mHighlightTill < millis()) { 253 | setInversion(mInverted); 254 | mHighlighted = false; 255 | } 256 | } 257 | --------------------------------------------------------------------------------