merge V23.12.16 (#556)
* Optimize Sun data calculation * Remove not required enum * Split config struct into different sub structs * Feature: Allow configuration of LWT QoS * Made resetreason methods static * Feature: Implement offset cache for "YieldDay" Thanks to @broth-itk for the idea! Fix: #1258 #1397 * Add Esp32-Stick-PoE-A * remove broken LilyGO_T_ETH_POE config, use device profile instead * Feature: High resolution Icon and PWA (Progressive Web App) functionality Fix: #1289 * webapp: Update dependencies * Initialize TaskScheduler * Migrate SunPosition to TaskScheduler * Migrate Datastore to TaskScheduler * Migrate MqttHandleInverterTotal to TaskSchedule * Migrate MqttHandleHass to TaskScheduler * Migrate MqttHandleDtu to TaskScheduler * Migrate MqttHandleInverter to TaskScheduler * Migrate LedSingle to TaskScheduler * Migrate NetworkSettings to TaskScheduler * Migrate InverterSettings to TaskScheduler * Migrate MessageOutput to TaskScheduler * Migrate Display_Graphic to TaskScheduler * Migrate WebApi to TaskScheduler * Split InverterSettings into multiple tasks * Calculate SunPosition only every 5 seconds * Split LedSingle into multiple tasks * Upgrade espMqttClient from 1.4.5 to 1.5.0 * Doc: Correct amount of MPP-Tracker * Added HMT-1600-4T and HMT-1800-4T to DevInfoParser Fix #1524 * Adjusted inverter names for HMS-1600/1800/2000-4T * Add channel count to description of detected inverter type (DevInfoParser) * Adjust device web api endpoint for dynamic led count * Feature: Added ability to change the brightness of the LEDs Based on the idea of @moritzlerch with several modifications like pwmTable and structure * webapp: Update dependencies * Update olikraus/U8g2 from 2.35.7 to 2.35.8 * Remove not required onWebsocketEvent * Remove code nesting * Introduce several const statements * Remove not required AsyncEventSource * Doc: Added byte specification to each command * Feature: Added basic Grid Profile parser which shows the used profile and version Other values are still outstanding. * Optimize AlarmLogParser to save memory * Add libfrozen to project to create constexpr maps * Feature: First version of GridProfile Parser which shows all values contained in the profile. * webapp: Update dependencies * Apply better variable names * Remove not required casts * Add additional compiler flags to prevent errors * Add const statement to several variables * Replace NULL by nullptr * Update bblanchon/ArduinoJson from 6.21.3 to 6.21.4 * Add const keyword to method parameters * Add const keyword to methods * Use references instead of pointers whenver possible * Adjust member variable names in MqttSettings * Adjust member variable names in NetworkSettings * webapp: Update timezone database to latest version * webapp: Beautify and unify form footers * Feature: Allow setting of an inverter limit of 0% and 0W Thanks to @madmartin in #1270 * Feature: Allow links in device profiles These links will be shown on the hardware settings page. * Doc: Added hint regarding HMS-xxxx-xT-NA inverters * Feature: Added DeviceProfile for CASmo-DTU Based on #1565 * Upgrade actions/upload-artifact from v3 to v4 * Upgrade actions/download-artifact from v3 to v4 * webapp: add app.js.gz * Gridprofileparser: Added latest known values Thanks to @stefan123t and @noone2k * webapp: Fix lint errors * Feature: Add DTU to Home Assistant Auto Discovery This is based on PR 1365 from @CFenner with several fixes and optimizations * Fix: Remove debug output as it floods the console * Fix: Gridprofileparser: Add additional error handling if profile is unknown * webapp: add app.js.gz * Fix: Offset cache for "YieldDay" did not work correctly * webapp: update dependencies * webapp: add app.js.gz * Fix: yarn.lock was outdated * Fix: yarn build error * Fix: Reset Yield day correction in combination with Zero Yield Day on Midnight lead to wrong values. * Fix: Allow negative values in GridProfileParser * Correct variable name * Fix #1579: Static IP in Ethernet mode did not work correctly * Feature: Added diagram to display This is based on the idea of @Henrik-Ingenieur and was discussed in #1504 * webapp: update dependencies * webapp: add app.js.gz --------- Co-authored-by: Thomas Basler <thomas@familie-basler.net> Co-authored-by: Pierre Kancir <pierre.kancir.emn@gmail.com>
This commit is contained in:
parent
fb2ca28692
commit
d494810975
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -106,7 +106,7 @@ jobs:
|
||||
- name: Rename Factory Firmware
|
||||
run: mv .pio/build/${{ matrix.environment }}/firmware.factory.bin .pio/build/${{ matrix.environment }}/opendtu-onbattery-${{ matrix.environment }}.factory.bin
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: opendtu-onbattery-${{ matrix.environment }}
|
||||
path: |
|
||||
@ -149,7 +149,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts/
|
||||
|
||||
|
||||
58
.vscode/settings.json
vendored
58
.vscode/settings.json
vendored
@ -2,6 +2,62 @@
|
||||
"C_Cpp.clang_format_style": "WebKit",
|
||||
"files.associations": {
|
||||
"*.tcc": "cpp",
|
||||
"algorithm": "cpp"
|
||||
"algorithm": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"map": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"regex": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"thread": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp"
|
||||
}
|
||||
}
|
||||
20
docs/DeviceProfiles/CASmo-DTU.json
Normal file
20
docs/DeviceProfiles/CASmo-DTU.json
Normal file
@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"name": "CASmo-DTU",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://casmo.info/product-details/?product=2"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
},
|
||||
"led": {
|
||||
"led0": 25,
|
||||
"led1": 26
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -1,6 +1,12 @@
|
||||
[
|
||||
{
|
||||
"name": "NRF, LEDs, Display",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-NRF-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HM-Serie-NRF-Modul/blink237542"},
|
||||
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
|
||||
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
|
||||
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
@ -21,6 +27,12 @@
|
||||
},
|
||||
{
|
||||
"name": "CMT, LEDs, Display",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-CMT-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HMS-und-HMT-Serie-CMT-Modul/blink238342"},
|
||||
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
|
||||
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
|
||||
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": -1,
|
||||
"mosi": -1,
|
||||
@ -49,6 +61,12 @@
|
||||
},
|
||||
{
|
||||
"name": "NRF, Display",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-NRF-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HM-Serie-NRF-Modul/blink237542"},
|
||||
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
|
||||
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
|
||||
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
@ -65,6 +83,12 @@
|
||||
},
|
||||
{
|
||||
"name": "CMT, Display",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-CMT-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HMS-und-HMT-Serie-CMT-Modul/blink238342"},
|
||||
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
|
||||
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
|
||||
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": -1,
|
||||
"mosi": -1,
|
||||
@ -89,6 +113,12 @@
|
||||
},
|
||||
{
|
||||
"name": "NRF, LEDs",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-NRF-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HM-Serie-NRF-Modul/blink237542"},
|
||||
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
|
||||
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
|
||||
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
@ -104,6 +134,12 @@
|
||||
},
|
||||
{
|
||||
"name": "CMT, LEDs",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-CMT-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HMS-und-HMT-Serie-CMT-Modul/blink238342"},
|
||||
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
|
||||
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
|
||||
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": -1,
|
||||
"mosi": -1,
|
||||
@ -127,6 +163,12 @@
|
||||
},
|
||||
{
|
||||
"name": "NRF",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-NRF-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HM-Serie-NRF-Modul/blink237542"},
|
||||
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
|
||||
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
|
||||
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
@ -138,6 +180,12 @@
|
||||
},
|
||||
{
|
||||
"name": "CMT",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-CMT-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HMS-und-HMT-Serie-CMT-Modul/blink238342"},
|
||||
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
|
||||
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
|
||||
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": -1,
|
||||
"mosi": -1,
|
||||
|
||||
25
docs/DeviceProfiles/esp32_stick_poe_a.json
Normal file
25
docs/DeviceProfiles/esp32_stick_poe_a.json
Normal file
@ -0,0 +1,25 @@
|
||||
[
|
||||
{
|
||||
"name": "Esp32-Stick-PoE-A",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://github.com/allexoK/Esp32-Stick-Boards-Docs"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 2,
|
||||
"mosi": 15,
|
||||
"clk": 14,
|
||||
"irq": 34,
|
||||
"en": 12,
|
||||
"cs": 4
|
||||
},
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 1,
|
||||
"power": -1,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 0,
|
||||
"clk_mode": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -1,6 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "LILYGO TTGO T-Internet-POE",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-internet-poe"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 2,
|
||||
"mosi": 15,
|
||||
@ -21,6 +24,9 @@
|
||||
},
|
||||
{
|
||||
"name": "LILYGO TTGO T-Internet-POE, nrf24 direct solder",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-internet-poe"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 12,
|
||||
"mosi": 4,
|
||||
@ -41,6 +47,9 @@
|
||||
},
|
||||
{
|
||||
"name": "LILYGO TTGO T-Internet-POE, nrf24 direct solder, SSD1306",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-internet-poe"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 12,
|
||||
"mosi": 4,
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "Olimex ESP32-EVB",
|
||||
"links": [
|
||||
{ "name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-EVB/open-source-hardware" }
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 15,
|
||||
"mosi": 2,
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "Olimex ESP32-POE",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 15,
|
||||
"mosi": 2,
|
||||
@ -21,6 +24,9 @@
|
||||
},
|
||||
{
|
||||
"name": "Olimex ESP32-POE with SSD1306",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 15,
|
||||
"mosi": 2,
|
||||
@ -46,6 +52,9 @@
|
||||
},
|
||||
{
|
||||
"name": "Olimex ESP32-POE with SH1106",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 15,
|
||||
"mosi": 2,
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "WT32-ETH01",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "http://www.wireless-tag.com/portfolio/wt32-eth01/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 4,
|
||||
"mosi": 2,
|
||||
@ -21,6 +24,9 @@
|
||||
},
|
||||
{
|
||||
"name": "WT32-ETH01 with SSD1306",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "http://www.wireless-tag.com/portfolio/wt32-eth01/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 4,
|
||||
"mosi": 2,
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#include "BatteryStats.h"
|
||||
|
||||
@ -19,12 +20,15 @@ class BatteryProvider {
|
||||
|
||||
class BatteryClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler&);
|
||||
void updateSettings();
|
||||
|
||||
std::shared_ptr<BatteryStats const> getStats() const;
|
||||
|
||||
private:
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
uint32_t _lastMqttPublish = 0;
|
||||
mutable std::mutex _mutex;
|
||||
std::unique_ptr<BatteryProvider> _upProvider = nullptr;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "PinMapping.h"
|
||||
#include <cstdint>
|
||||
|
||||
#define CONFIG_FILENAME "/config.json"
|
||||
@ -57,6 +58,7 @@ struct INVERTER_CONFIG_T {
|
||||
uint8_t ReachableThreshold;
|
||||
bool ZeroRuntimeDataIfUnrechable;
|
||||
bool ZeroYieldDayOnMidnight;
|
||||
bool YieldDayCorrection;
|
||||
CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT];
|
||||
};
|
||||
|
||||
@ -74,128 +76,171 @@ struct POWERMETER_HTTP_PHASE_CONFIG_T {
|
||||
};
|
||||
|
||||
struct CONFIG_T {
|
||||
uint32_t Cfg_Version;
|
||||
uint32_t Cfg_SaveCount;
|
||||
struct {
|
||||
uint32_t Version;
|
||||
uint32_t SaveCount;
|
||||
} Cfg;
|
||||
|
||||
char WiFi_Ssid[WIFI_MAX_SSID_STRLEN + 1];
|
||||
char WiFi_Password[WIFI_MAX_PASSWORD_STRLEN + 1];
|
||||
uint8_t WiFi_Ip[4];
|
||||
uint8_t WiFi_Netmask[4];
|
||||
uint8_t WiFi_Gateway[4];
|
||||
uint8_t WiFi_Dns1[4];
|
||||
uint8_t WiFi_Dns2[4];
|
||||
bool WiFi_Dhcp;
|
||||
char WiFi_Hostname[WIFI_MAX_HOSTNAME_STRLEN + 1];
|
||||
uint32_t WiFi_ApTimeout;
|
||||
struct {
|
||||
char Ssid[WIFI_MAX_SSID_STRLEN + 1];
|
||||
char Password[WIFI_MAX_PASSWORD_STRLEN + 1];
|
||||
uint8_t Ip[4];
|
||||
uint8_t Netmask[4];
|
||||
uint8_t Gateway[4];
|
||||
uint8_t Dns1[4];
|
||||
uint8_t Dns2[4];
|
||||
bool Dhcp;
|
||||
char Hostname[WIFI_MAX_HOSTNAME_STRLEN + 1];
|
||||
uint32_t ApTimeout;
|
||||
} WiFi;
|
||||
|
||||
bool Mdns_Enabled;
|
||||
struct {
|
||||
bool Enabled;
|
||||
} Mdns;
|
||||
|
||||
char Ntp_Server[NTP_MAX_SERVER_STRLEN + 1];
|
||||
char Ntp_Timezone[NTP_MAX_TIMEZONE_STRLEN + 1];
|
||||
char Ntp_TimezoneDescr[NTP_MAX_TIMEZONEDESCR_STRLEN + 1];
|
||||
double Ntp_Longitude;
|
||||
double Ntp_Latitude;
|
||||
uint8_t Ntp_SunsetType;
|
||||
struct {
|
||||
char Server[NTP_MAX_SERVER_STRLEN + 1];
|
||||
char Timezone[NTP_MAX_TIMEZONE_STRLEN + 1];
|
||||
char TimezoneDescr[NTP_MAX_TIMEZONEDESCR_STRLEN + 1];
|
||||
double Longitude;
|
||||
double Latitude;
|
||||
uint8_t SunsetType;
|
||||
} Ntp;
|
||||
|
||||
struct {
|
||||
bool Enabled;
|
||||
char Hostname[MQTT_MAX_HOSTNAME_STRLEN + 1];
|
||||
bool VerboseLogging;
|
||||
uint32_t Port;
|
||||
char Username[MQTT_MAX_USERNAME_STRLEN + 1];
|
||||
char Password[MQTT_MAX_PASSWORD_STRLEN + 1];
|
||||
char Topic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
bool Retain;
|
||||
uint32_t PublishInterval;
|
||||
bool CleanSession;
|
||||
|
||||
struct {
|
||||
char Topic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
char Value_Online[MQTT_MAX_LWTVALUE_STRLEN + 1];
|
||||
char Value_Offline[MQTT_MAX_LWTVALUE_STRLEN + 1];
|
||||
uint8_t Qos;
|
||||
} Lwt;
|
||||
|
||||
struct {
|
||||
bool Enabled;
|
||||
bool Retain;
|
||||
char Topic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
bool IndividualPanels;
|
||||
bool Expire;
|
||||
} Hass;
|
||||
|
||||
struct {
|
||||
bool Enabled;
|
||||
char RootCaCert[MQTT_MAX_CERT_STRLEN + 1];
|
||||
bool CertLogin;
|
||||
char ClientCert[MQTT_MAX_CERT_STRLEN + 1];
|
||||
char ClientKey[MQTT_MAX_CERT_STRLEN + 1];
|
||||
} Tls;
|
||||
} Mqtt;
|
||||
|
||||
struct {
|
||||
uint64_t Serial;
|
||||
uint32_t PollInterval;
|
||||
struct {
|
||||
uint8_t PaLevel;
|
||||
} Nrf;
|
||||
struct {
|
||||
int8_t PaLevel;
|
||||
uint32_t Frequency;
|
||||
} Cmt;
|
||||
bool VerboseLogging;
|
||||
} Dtu;
|
||||
|
||||
struct {
|
||||
char Password[WIFI_MAX_PASSWORD_STRLEN + 1];
|
||||
bool AllowReadonly;
|
||||
} Security;
|
||||
|
||||
struct {
|
||||
bool PowerSafe;
|
||||
bool ScreenSaver;
|
||||
uint8_t Rotation;
|
||||
uint8_t Contrast;
|
||||
uint8_t Language;
|
||||
uint32_t DiagramDuration;
|
||||
} Display;
|
||||
|
||||
struct {
|
||||
uint8_t Brightness;
|
||||
} Led_Single[PINMAPPING_LED_COUNT];
|
||||
|
||||
struct {
|
||||
bool Enabled;
|
||||
bool VerboseLogging;
|
||||
bool UpdatesOnly;
|
||||
} Vedirect;
|
||||
|
||||
struct {
|
||||
bool Enabled;
|
||||
bool VerboseLogging;
|
||||
uint32_t Interval;
|
||||
uint32_t Source;
|
||||
char MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
char MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
char MqttTopicPowerMeter3[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
uint32_t SdmBaudrate;
|
||||
uint32_t SdmAddress;
|
||||
uint32_t HttpInterval;
|
||||
bool HttpIndividualRequests;
|
||||
POWERMETER_HTTP_PHASE_CONFIG_T Http_Phase[POWERMETER_MAX_PHASES];
|
||||
} PowerMeter;
|
||||
|
||||
struct {
|
||||
bool Enabled;
|
||||
bool VerboseLogging;
|
||||
bool SolarPassThroughEnabled;
|
||||
uint8_t SolarPassThroughLosses;
|
||||
uint8_t BatteryDrainStategy;
|
||||
uint32_t Interval;
|
||||
bool IsInverterBehindPowerMeter;
|
||||
uint8_t InverterId;
|
||||
uint8_t InverterChannelId;
|
||||
int32_t TargetPowerConsumption;
|
||||
int32_t TargetPowerConsumptionHysteresis;
|
||||
int32_t LowerPowerLimit;
|
||||
int32_t UpperPowerLimit;
|
||||
uint32_t BatterySocStartThreshold;
|
||||
uint32_t BatterySocStopThreshold;
|
||||
float VoltageStartThreshold;
|
||||
float VoltageStopThreshold;
|
||||
float VoltageLoadCorrectionFactor;
|
||||
int8_t RestartHour;
|
||||
uint32_t FullSolarPassThroughSoc;
|
||||
float FullSolarPassThroughStartVoltage;
|
||||
float FullSolarPassThroughStopVoltage;
|
||||
} PowerLimiter;
|
||||
|
||||
struct {
|
||||
bool Enabled;
|
||||
bool VerboseLogging;
|
||||
uint8_t Provider;
|
||||
uint8_t JkBmsInterface;
|
||||
uint8_t JkBmsPollingInterval;
|
||||
} Battery;
|
||||
|
||||
struct {
|
||||
bool Enabled;
|
||||
uint32_t CAN_Controller_Frequency;
|
||||
bool Auto_Power_Enabled;
|
||||
float Auto_Power_Voltage_Limit;
|
||||
float Auto_Power_Enable_Voltage_Limit;
|
||||
float Auto_Power_Lower_Power_Limit;
|
||||
float Auto_Power_Upper_Power_Limit;
|
||||
} Huawei;
|
||||
|
||||
bool Mqtt_Enabled;
|
||||
char Mqtt_Hostname[MQTT_MAX_HOSTNAME_STRLEN + 1];
|
||||
bool Mqtt_VerboseLogging;
|
||||
uint32_t Mqtt_Port;
|
||||
char Mqtt_Username[MQTT_MAX_USERNAME_STRLEN + 1];
|
||||
char Mqtt_Password[MQTT_MAX_PASSWORD_STRLEN + 1];
|
||||
char Mqtt_Topic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
bool Mqtt_Retain;
|
||||
char Mqtt_LwtTopic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
char Mqtt_LwtValue_Online[MQTT_MAX_LWTVALUE_STRLEN + 1];
|
||||
char Mqtt_LwtValue_Offline[MQTT_MAX_LWTVALUE_STRLEN + 1];
|
||||
uint32_t Mqtt_PublishInterval;
|
||||
bool Mqtt_CleanSession;
|
||||
|
||||
INVERTER_CONFIG_T Inverter[INV_MAX_COUNT];
|
||||
|
||||
uint64_t Dtu_Serial;
|
||||
uint32_t Dtu_PollInterval;
|
||||
bool Dtu_VerboseLogging;
|
||||
uint8_t Dtu_NrfPaLevel;
|
||||
int8_t Dtu_CmtPaLevel;
|
||||
uint32_t Dtu_CmtFrequency;
|
||||
|
||||
bool Mqtt_Hass_Enabled;
|
||||
bool Mqtt_Hass_Retain;
|
||||
char Mqtt_Hass_Topic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
bool Mqtt_Hass_IndividualPanels;
|
||||
bool Mqtt_Hass_Expire;
|
||||
|
||||
bool Mqtt_Tls;
|
||||
char Mqtt_RootCaCert[MQTT_MAX_CERT_STRLEN + 1];
|
||||
bool Mqtt_TlsCertLogin;
|
||||
char Mqtt_ClientCert[MQTT_MAX_CERT_STRLEN + 1];
|
||||
char Mqtt_ClientKey[MQTT_MAX_CERT_STRLEN +1];
|
||||
|
||||
bool Vedirect_Enabled;
|
||||
bool Vedirect_VerboseLogging;
|
||||
bool Vedirect_UpdatesOnly;
|
||||
|
||||
bool PowerMeter_Enabled;
|
||||
bool PowerMeter_VerboseLogging;
|
||||
uint32_t PowerMeter_Interval;
|
||||
uint32_t PowerMeter_Source;
|
||||
char PowerMeter_MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
char PowerMeter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
char PowerMeter_MqttTopicPowerMeter3[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||
uint32_t PowerMeter_SdmBaudrate;
|
||||
uint32_t PowerMeter_SdmAddress;
|
||||
uint32_t PowerMeter_HttpInterval;
|
||||
bool PowerMeter_HttpIndividualRequests;
|
||||
POWERMETER_HTTP_PHASE_CONFIG_T Powermeter_Http_Phase[POWERMETER_MAX_PHASES];
|
||||
|
||||
bool PowerLimiter_Enabled;
|
||||
bool PowerLimiter_VerboseLogging;
|
||||
bool PowerLimiter_SolarPassThroughEnabled;
|
||||
uint8_t PowerLimiter_SolarPassThroughLosses;
|
||||
uint8_t PowerLimiter_BatteryDrainStategy;
|
||||
uint32_t PowerLimiter_Interval;
|
||||
bool PowerLimiter_IsInverterBehindPowerMeter;
|
||||
uint8_t PowerLimiter_InverterId;
|
||||
uint8_t PowerLimiter_InverterChannelId;
|
||||
int32_t PowerLimiter_TargetPowerConsumption;
|
||||
int32_t PowerLimiter_TargetPowerConsumptionHysteresis;
|
||||
int32_t PowerLimiter_LowerPowerLimit;
|
||||
int32_t PowerLimiter_UpperPowerLimit;
|
||||
uint32_t PowerLimiter_BatterySocStartThreshold;
|
||||
uint32_t PowerLimiter_BatterySocStopThreshold;
|
||||
float PowerLimiter_VoltageStartThreshold;
|
||||
float PowerLimiter_VoltageStopThreshold;
|
||||
float PowerLimiter_VoltageLoadCorrectionFactor;
|
||||
int8_t PowerLimiter_RestartHour;
|
||||
uint32_t PowerLimiter_FullSolarPassThroughSoc;
|
||||
float PowerLimiter_FullSolarPassThroughStartVoltage;
|
||||
float PowerLimiter_FullSolarPassThroughStopVoltage;
|
||||
|
||||
bool Battery_Enabled;
|
||||
bool Battery_VerboseLogging;
|
||||
uint8_t Battery_Provider;
|
||||
uint8_t Battery_JkBmsInterface;
|
||||
uint8_t Battery_JkBmsPollingInterval;
|
||||
|
||||
bool Huawei_Enabled;
|
||||
uint32_t Huawei_CAN_Controller_Frequency;
|
||||
bool Huawei_Auto_Power_Enabled;
|
||||
float Huawei_Auto_Power_Voltage_Limit;
|
||||
float Huawei_Auto_Power_Enable_Voltage_Limit;
|
||||
float Huawei_Auto_Power_Lower_Power_Limit;
|
||||
float Huawei_Auto_Power_Upper_Power_Limit;
|
||||
|
||||
char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1];
|
||||
bool Security_AllowReadonly;
|
||||
|
||||
char Dev_PinMapping[DEV_MAX_MAPPING_NAME_STRLEN + 1];
|
||||
|
||||
bool Display_PowerSafe;
|
||||
bool Display_ScreenSaver;
|
||||
uint8_t Display_Rotation;
|
||||
uint8_t Display_Contrast;
|
||||
uint8_t Display_Language;
|
||||
};
|
||||
|
||||
class ConfigurationClass {
|
||||
@ -207,7 +252,7 @@ public:
|
||||
CONFIG_T& get();
|
||||
|
||||
INVERTER_CONFIG_T* getFreeInverterSlot();
|
||||
INVERTER_CONFIG_T* getInverterConfig(uint64_t serial);
|
||||
INVERTER_CONFIG_T* getInverterConfig(const uint64_t serial);
|
||||
};
|
||||
|
||||
extern ConfigurationClass Configuration;
|
||||
@ -1,13 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <TimeoutHelper.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <mutex>
|
||||
|
||||
class DatastoreClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
// Sum of yield total of all enabled inverters, a inverter which is just disabled at night is also included
|
||||
float getTotalAcYieldTotalEnabled();
|
||||
@ -58,7 +57,10 @@ public:
|
||||
bool getIsAllEnabledReachable();
|
||||
|
||||
private:
|
||||
TimeoutHelper _updateTimeout;
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
std::mutex _mutex;
|
||||
|
||||
float _totalAcYieldTotalEnabled = 0;
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "Display_Graphic_Diagram.h"
|
||||
#include "defaults.h"
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <U8g2lib.h>
|
||||
|
||||
enum DisplayType_t {
|
||||
@ -16,23 +18,28 @@ public:
|
||||
DisplayGraphicClass();
|
||||
~DisplayGraphicClass();
|
||||
|
||||
void init(DisplayType_t type, uint8_t data, uint8_t clk, uint8_t cs, uint8_t reset);
|
||||
void loop();
|
||||
void setContrast(uint8_t contrast);
|
||||
void setStatus(bool turnOn);
|
||||
void setOrientation(uint8_t rotation = DISPLAY_ROTATION);
|
||||
void setLanguage(uint8_t language);
|
||||
void init(Scheduler& scheduler, const DisplayType_t type, const uint8_t data, const uint8_t clk, const uint8_t cs, const uint8_t reset);
|
||||
void setContrast(const uint8_t contrast);
|
||||
void setStatus(const bool turnOn);
|
||||
void setOrientation(const uint8_t rotation = DISPLAY_ROTATION);
|
||||
void setLanguage(const uint8_t language);
|
||||
void setStartupDisplay();
|
||||
|
||||
DisplayGraphicDiagramClass& Diagram();
|
||||
|
||||
bool enablePowerSafe = true;
|
||||
bool enableScreensaver = true;
|
||||
|
||||
private:
|
||||
void printText(const char* text, uint8_t line);
|
||||
void loop();
|
||||
void printText(const char* text, const uint8_t line);
|
||||
void calcLineHeights();
|
||||
void setFont(uint8_t line);
|
||||
void setFont(const uint8_t line);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
U8G2* _display;
|
||||
DisplayGraphicDiagramClass _diagram;
|
||||
|
||||
bool _displayTurnedOn;
|
||||
|
||||
@ -41,7 +48,6 @@ private:
|
||||
uint8_t _mExtra;
|
||||
uint16_t _period = 1000;
|
||||
uint16_t _interval = 60000; // interval at which to power save (milliseconds)
|
||||
uint32_t _lastDisplayUpdate = 0;
|
||||
uint32_t _previousMillis = 0;
|
||||
char _fmtText[32];
|
||||
bool _isLarge = false;
|
||||
|
||||
39
include/Display_Graphic_Diagram.h
Normal file
39
include/Display_Graphic_Diagram.h
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <U8g2lib.h>
|
||||
#include <array>
|
||||
|
||||
#define CHART_HEIGHT 20 // chart area hight in pixels
|
||||
#define CHART_WIDTH 47 // chart area width in pixels
|
||||
#define DIAG_POSX 80 // position were Diag is drawn at
|
||||
#define DIAG_POSY 0
|
||||
|
||||
class DisplayGraphicDiagramClass {
|
||||
public:
|
||||
DisplayGraphicDiagramClass();
|
||||
|
||||
void init(Scheduler& scheduler, U8G2* display);
|
||||
void redraw();
|
||||
|
||||
void updatePeriod();
|
||||
|
||||
private:
|
||||
void averageLoop();
|
||||
void dataPointLoop();
|
||||
|
||||
static uint32_t getSecondsPerDot();
|
||||
|
||||
Task _averageTask;
|
||||
Task _dataPointTask;
|
||||
|
||||
U8G2* _display = nullptr;
|
||||
std::array<float, CHART_WIDTH> _graphValues = {};
|
||||
uint8_t _graphValuesCount = 0;
|
||||
|
||||
float _iRunningAverage = 0;
|
||||
uint16_t _iRunningAverageCnt = 0;
|
||||
|
||||
uint8_t _graphPosX = DIAG_POSX;
|
||||
};
|
||||
@ -5,6 +5,7 @@
|
||||
#include "SPI.h"
|
||||
#include <mcp_can.h>
|
||||
#include <mutex>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#ifndef HUAWEI_PIN_MISO
|
||||
#define HUAWEI_PIN_MISO 12
|
||||
@ -118,8 +119,8 @@ private:
|
||||
|
||||
class HuaweiCanClass {
|
||||
public:
|
||||
void init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs, uint8_t huawei_power);
|
||||
void loop();
|
||||
void init(Scheduler& scheduler, uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs, uint8_t huawei_power);
|
||||
void updateSettings(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs, uint8_t huawei_power);
|
||||
void setValue(float in, uint8_t parameterType);
|
||||
void setMode(uint8_t mode);
|
||||
|
||||
@ -128,9 +129,12 @@ public:
|
||||
bool getAutoPowerStatus();
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void processReceivedParameters();
|
||||
void _setValue(float in, uint8_t parameterType);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
TaskHandle_t _HuaweiCanCommunicationTaskHdl = NULL;
|
||||
bool _initialized = false;
|
||||
uint8_t _huaweiPower; // Power pin
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <cstdint>
|
||||
|
||||
#define INVERTER_UPDATE_SETTINGS_INTERVAL 60000l
|
||||
|
||||
class InverterSettingsClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
uint32_t _lastUpdate = 0;
|
||||
void settingsLoop();
|
||||
void hoyLoop();
|
||||
|
||||
Task _settingsTask;
|
||||
Task _hoyTask;
|
||||
};
|
||||
|
||||
extern InverterSettingsClass InverterSettings;
|
||||
|
||||
@ -2,38 +2,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "PinMapping.h"
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <TimeoutHelper.h>
|
||||
|
||||
#define LEDSINGLE_UPDATE_INTERVAL 2000
|
||||
|
||||
enum eLedFunction {
|
||||
CONNECTED_NETWORK,
|
||||
CONNECTED_MQTT,
|
||||
INV_REACHABLE,
|
||||
INV_PRODUCING,
|
||||
};
|
||||
|
||||
class LedSingleClass {
|
||||
public:
|
||||
LedSingleClass();
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
void turnAllOff();
|
||||
void turnAllOn();
|
||||
|
||||
private:
|
||||
void setLoop();
|
||||
void outputLoop();
|
||||
|
||||
void setLed(const uint8_t ledNo, const bool ledState);
|
||||
|
||||
Task _setTask;
|
||||
Task _outputTask;
|
||||
|
||||
enum class LedState_t {
|
||||
On,
|
||||
Off,
|
||||
Blink,
|
||||
};
|
||||
|
||||
LedState_t _ledState[PINMAPPING_LED_COUNT];
|
||||
LedState_t _allState;
|
||||
TimeoutHelper _updateTimeout;
|
||||
LedState_t _ledMode[PINMAPPING_LED_COUNT];
|
||||
LedState_t _allMode;
|
||||
bool _ledStateCurrent[PINMAPPING_LED_COUNT];
|
||||
TimeoutHelper _blinkTimeout;
|
||||
uint8_t _ledActive = 0;
|
||||
};
|
||||
|
||||
extern LedSingleClass LedSingle;
|
||||
@ -2,34 +2,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <AsyncWebSocket.h>
|
||||
#include <Print.h>
|
||||
#include <freertos/task.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Stream.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
#define BUFFER_SIZE 500
|
||||
|
||||
class MessageOutputClass : public Print {
|
||||
public:
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
size_t write(uint8_t c) override;
|
||||
size_t write(const uint8_t *buffer, size_t size) override;
|
||||
size_t write(const uint8_t* buffer, size_t size) override;
|
||||
void register_ws_output(AsyncWebSocket* output);
|
||||
|
||||
private:
|
||||
using message_t = std::vector<uint8_t>;
|
||||
void loop();
|
||||
|
||||
// we keep a buffer for every task and only write complete lines to the
|
||||
// serial output and then move them to be pushed through the websocket.
|
||||
// this way we prevent mangling of messages from different contexts.
|
||||
std::unordered_map<TaskHandle_t, message_t> _task_messages;
|
||||
std::queue<message_t> _lines;
|
||||
Task _loopTask;
|
||||
|
||||
AsyncWebSocket* _ws = nullptr;
|
||||
char _buffer[BUFFER_SIZE];
|
||||
uint16_t _buff_pos = 0;
|
||||
uint32_t _lastSend = 0;
|
||||
bool _forceSend = false;
|
||||
|
||||
std::mutex _msgLock;
|
||||
|
||||
void serialWrite(message_t const& m);
|
||||
};
|
||||
|
||||
extern MessageOutputClass MessageOutput;
|
||||
@ -1,15 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <cstdint>
|
||||
|
||||
class MqttHandleDtuClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
uint32_t _lastPublish = 0;
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
};
|
||||
|
||||
extern MqttHandleDtuClass MqttHandleDtu;
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <Hoymiles.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
// mqtt discovery device classes
|
||||
enum {
|
||||
@ -50,18 +51,29 @@ const byteAssign_fieldDeviceClass_t deviceFieldAssignment[] = {
|
||||
|
||||
class MqttHandleHassClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
void publishConfig();
|
||||
void forceUpdate();
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void publish(const String& subtopic, const String& payload);
|
||||
void publishField(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, byteAssign_fieldDeviceClass_t fieldType, bool clear = false);
|
||||
void publishDtuSensor(const char* name, const char* device_class, const char* category, const char* icon, const char* unit_of_measure, const char* subTopic);
|
||||
void publishDtuBinarySensor(const char* name, const char* device_class, const char* category, const char* payload_on, const char* payload_off, const char* subTopic = "");
|
||||
void publishInverterField(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const byteAssign_fieldDeviceClass_t fieldType, const bool clear = false);
|
||||
void publishInverterButton(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* deviceClass, const char* subTopic, const char* payload);
|
||||
void publishInverterNumber(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic, const char* unitOfMeasure, int16_t min = 1, int16_t max = 100);
|
||||
void publishInverterNumber(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic, const char* unitOfMeasure, const int16_t min = 1, const int16_t max = 100);
|
||||
void publishInverterBinarySensor(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* subTopic, const char* payload_on, const char* payload_off);
|
||||
void createDeviceInfo(JsonObject& object, std::shared_ptr<InverterAbstract> inv);
|
||||
|
||||
static void createInverterInfo(DynamicJsonDocument& doc, std::shared_ptr<InverterAbstract> inv);
|
||||
static void createDtuInfo(DynamicJsonDocument& doc);
|
||||
|
||||
static void createDeviceInfo(DynamicJsonDocument& doc, const String& name, const String& identifiers, const String& configuration_url, const String& manufacturer, const String& model, const String& sw_version, const String& via_device = "");
|
||||
|
||||
static String getDtuUniqueId();
|
||||
static String getDtuUrl();
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
bool _wasConnected = false;
|
||||
bool _updateForced = false;
|
||||
|
||||
@ -4,15 +4,18 @@
|
||||
#include "Configuration.h"
|
||||
#include <Huawei_can.h>
|
||||
#include <espMqttClient.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class MqttHandleHuaweiClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
uint32_t _lastPublishStats;
|
||||
uint32_t _lastPublish;
|
||||
|
||||
|
||||
@ -3,22 +3,23 @@
|
||||
|
||||
#include "Configuration.h"
|
||||
#include <Hoymiles.h>
|
||||
#include <TimeoutHelper.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <espMqttClient.h>
|
||||
|
||||
class MqttHandleInverterClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
static String getTopic(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
static String getTopic(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId);
|
||||
|
||||
private:
|
||||
void publishField(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
|
||||
void loop();
|
||||
void publishField(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId);
|
||||
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, const size_t len, const size_t index, const size_t total);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
uint32_t _lastPublishStats[INV_MAX_COUNT] = { 0 };
|
||||
uint32_t _lastPublish = 0;
|
||||
|
||||
FieldId_t _publishFields[14] = {
|
||||
FLD_UDC,
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <TimeoutHelper.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class MqttHandleInverterTotalClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
TimeoutHelper _lastPublish;
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
};
|
||||
|
||||
extern MqttHandleInverterTotalClass MqttHandleInverterTotal;
|
||||
@ -3,15 +3,18 @@
|
||||
|
||||
#include "Configuration.h"
|
||||
#include <espMqttClient.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class MqttHandlePowerLimiterClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void onCmdMode(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
uint32_t _lastPublishStats;
|
||||
uint32_t _lastPublish;
|
||||
|
||||
|
||||
@ -2,20 +2,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class MqttHandlePylontechHassClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
void publishConfig();
|
||||
void forceUpdate();
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void publish(const String& subtopic, const String& payload);
|
||||
void publishBinarySensor(const char* caption, const char* icon, const char* subTopic, const char* payload_on, const char* payload_off);
|
||||
void publishSensor(const char* caption, const char* icon, const char* subTopic, const char* deviceClass = NULL, const char* stateClass = NULL, const char* unitOfMeasurement = NULL);
|
||||
void createDeviceInfo(JsonObject& object);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
bool _wasConnected = false;
|
||||
bool _updateForced = false;
|
||||
String serial = "0001"; // pseudo-serial, can be replaced in future with real serialnumber
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "VeDirectMpptController.h"
|
||||
#include "Configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#ifndef VICTRON_PIN_RX
|
||||
#define VICTRON_PIN_RX 22
|
||||
@ -15,12 +16,14 @@
|
||||
|
||||
class MqttHandleVedirectClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
void forceUpdate();
|
||||
private:
|
||||
|
||||
void loop();
|
||||
VeDirectMpptController::veMpptStruct _kvFrame{};
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
// point of time in millis() when updated values will be published
|
||||
uint32_t _nextPublishUpdatesOnly = 0;
|
||||
|
||||
|
||||
@ -3,20 +3,23 @@
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include "VeDirectMpptController.h"
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class MqttHandleVedirectHassClass {
|
||||
public:
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
void publishConfig();
|
||||
void forceUpdate();
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void publish(const String& subtopic, const String& payload);
|
||||
void publishBinarySensor(const char* caption, const char* icon, const char* subTopic, const char* payload_on, const char* payload_off);
|
||||
void publishSensor(const char* caption, const char* icon, const char* subTopic, const char* deviceClass = NULL, const char* stateClass = NULL, const char* unitOfMeasurement = NULL);
|
||||
void createDeviceInfo(JsonObject& object);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
bool _wasConnected = false;
|
||||
bool _updateForced = false;
|
||||
};
|
||||
|
||||
@ -15,29 +15,27 @@ public:
|
||||
void performReconnect();
|
||||
bool getConnected();
|
||||
void publish(const String& subtopic, const String& payload);
|
||||
void publishGeneric(const String& topic, const String& payload, bool retain, uint8_t qos = 0);
|
||||
void publishGeneric(const String& topic, const String& payload, const bool retain, const uint8_t qos = 0);
|
||||
|
||||
void subscribe(const String& topic, uint8_t qos, const espMqttClientTypes::OnMessageCallback& cb);
|
||||
void subscribe(const String& topic, const uint8_t qos, const espMqttClientTypes::OnMessageCallback& cb);
|
||||
void unsubscribe(const String& topic);
|
||||
|
||||
String getPrefix();
|
||||
String getPrefix() const;
|
||||
|
||||
private:
|
||||
void NetworkEvent(network_event event);
|
||||
|
||||
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
|
||||
void onMqttConnect(const bool sessionPresent);
|
||||
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, const size_t len, const size_t index, const size_t total);
|
||||
|
||||
void performConnect();
|
||||
void performDisconnect();
|
||||
|
||||
void createMqttClientObject();
|
||||
|
||||
MqttClient* mqttClient = nullptr;
|
||||
String clientId;
|
||||
String willTopic;
|
||||
Ticker mqttReconnectTimer;
|
||||
MqttClient* _mqttClient = nullptr;
|
||||
Ticker _mqttReconnectTimer;
|
||||
MqttSubscribeParser _mqttSubscribeParser;
|
||||
std::mutex _clientLock;
|
||||
bool _verboseLogging = true;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <DNSServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <WiFi.h>
|
||||
#include <vector>
|
||||
|
||||
@ -29,7 +30,7 @@ typedef struct NetworkEventCbList {
|
||||
network_event event;
|
||||
|
||||
NetworkEventCbList()
|
||||
: cb(NULL)
|
||||
: cb(nullptr)
|
||||
, event(network_event::NETWORK_UNKNOWN)
|
||||
{
|
||||
}
|
||||
@ -38,46 +39,50 @@ typedef struct NetworkEventCbList {
|
||||
class NetworkSettingsClass {
|
||||
public:
|
||||
NetworkSettingsClass();
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
void applyConfig();
|
||||
void enableAdminMode();
|
||||
String getApName();
|
||||
String getApName() const;
|
||||
|
||||
IPAddress localIP();
|
||||
IPAddress subnetMask();
|
||||
IPAddress gatewayIP();
|
||||
IPAddress dnsIP(uint8_t dns_no = 0);
|
||||
String macAddress();
|
||||
IPAddress localIP() const;
|
||||
IPAddress subnetMask() const;
|
||||
IPAddress gatewayIP() const;
|
||||
IPAddress dnsIP(const uint8_t dns_no = 0) const;
|
||||
String macAddress() const;
|
||||
static String getHostname();
|
||||
bool isConnected();
|
||||
network_mode NetworkMode();
|
||||
bool isConnected() const;
|
||||
network_mode NetworkMode() const;
|
||||
|
||||
bool onEvent(NetworkEventCb cbEvent, network_event event = network_event::NETWORK_EVENT_MAX);
|
||||
void raiseEvent(network_event event);
|
||||
bool onEvent(NetworkEventCb cbEvent, const network_event event = network_event::NETWORK_EVENT_MAX);
|
||||
void raiseEvent(const network_event event);
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void setHostname();
|
||||
void setStaticIp();
|
||||
void handleMDNS();
|
||||
void setupMode();
|
||||
void NetworkEvent(WiFiEvent_t event);
|
||||
bool adminEnabled = true;
|
||||
bool forceDisconnection = false;
|
||||
uint32_t adminTimeoutCounter = 0;
|
||||
uint32_t adminTimeoutCounterMax = 0;
|
||||
uint32_t connectTimeoutTimer = 0;
|
||||
uint32_t connectRedoTimer = 0;
|
||||
uint32_t lastTimerCall = 0;
|
||||
const byte DNS_PORT = 53;
|
||||
IPAddress apIp;
|
||||
IPAddress apNetmask;
|
||||
std::unique_ptr<DNSServer> dnsServer;
|
||||
bool dnsServerStatus = false;
|
||||
void NetworkEvent(const WiFiEvent_t event);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
static constexpr byte DNS_PORT = 53;
|
||||
|
||||
bool _adminEnabled = true;
|
||||
bool _forceDisconnection = false;
|
||||
uint32_t _adminTimeoutCounter = 0;
|
||||
uint32_t _adminTimeoutCounterMax = 0;
|
||||
uint32_t _connectTimeoutTimer = 0;
|
||||
uint32_t _connectRedoTimer = 0;
|
||||
uint32_t _lastTimerCall = 0;
|
||||
IPAddress _apIp;
|
||||
IPAddress _apNetmask;
|
||||
std::unique_ptr<DNSServer> _dnsServer;
|
||||
bool _dnsServerStatus = false;
|
||||
network_mode _networkMode = network_mode::Undefined;
|
||||
bool _ethConnected = false;
|
||||
std::vector<NetworkEventCbList_t> _cbEventList;
|
||||
bool lastMdnsEnabled = false;
|
||||
bool _lastMdnsEnabled = false;
|
||||
};
|
||||
|
||||
extern NetworkSettingsClass NetworkSettings;
|
||||
@ -59,9 +59,9 @@ public:
|
||||
bool init(const String& deviceMapping);
|
||||
PinMapping_t& get();
|
||||
|
||||
bool isValidNrf24Config();
|
||||
bool isValidCmt2300Config();
|
||||
bool isValidEthConfig();
|
||||
bool isValidNrf24Config() const;
|
||||
bool isValidCmt2300Config() const;
|
||||
bool isValidEthConfig() const;
|
||||
bool isValidHuaweiConfig();
|
||||
|
||||
private:
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <Hoymiles.h>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#define PL_UI_STATE_INACTIVE 0
|
||||
#define PL_UI_STATE_CHARGING 1
|
||||
@ -47,8 +48,7 @@ public:
|
||||
Stable,
|
||||
};
|
||||
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
uint8_t getPowerLimiterState();
|
||||
int32_t getLastRequestedPowerLimit();
|
||||
|
||||
@ -63,6 +63,10 @@ public:
|
||||
void calcNextInverterRestart();
|
||||
|
||||
private:
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
int32_t _lastRequestedPowerLimit = 0;
|
||||
uint32_t _lastPowerLimitMillis = 0;
|
||||
uint32_t _shutdownTimeout = 0;
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <list>
|
||||
#include "SDM.h"
|
||||
#include "sml.h"
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#ifndef SDM_RX_PIN
|
||||
#define SDM_RX_PIN 13
|
||||
@ -36,17 +37,19 @@ public:
|
||||
SOURCE_HTTP = 3,
|
||||
SOURCE_SML = 4
|
||||
};
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
float getPowerTotal(bool forceUpdate = true);
|
||||
uint32_t getLastPowerMeterUpdate();
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void mqtt();
|
||||
|
||||
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties,
|
||||
const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
bool _verboseLogging = true;
|
||||
uint32_t _lastPowerMeterCheck;
|
||||
// Used in Power limiter for safety check
|
||||
|
||||
6
include/Scheduler.h
Normal file
6
include/Scheduler.h
Normal file
@ -0,0 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
extern Scheduler scheduler;
|
||||
@ -1,34 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <atomic>
|
||||
#include <sunset.h>
|
||||
|
||||
class SunPositionClass {
|
||||
public:
|
||||
SunPositionClass();
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
bool isDayPeriod();
|
||||
bool isSunsetAvailable();
|
||||
bool sunsetTime(struct tm* info);
|
||||
bool sunriseTime(struct tm* info);
|
||||
void setDoRecalc(bool doRecalc);
|
||||
bool isDayPeriod() const;
|
||||
bool isSunsetAvailable() const;
|
||||
bool sunsetTime(struct tm* info) const;
|
||||
bool sunriseTime(struct tm* info) const;
|
||||
void setDoRecalc(const bool doRecalc);
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void updateSunData();
|
||||
bool checkRecalcDayChanged();
|
||||
bool getDoRecalc();
|
||||
bool checkRecalcDayChanged() const;
|
||||
bool getSunTime(struct tm* info, const uint32_t offset) const;
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
SunSet _sun;
|
||||
bool _isSunsetAvailable = true;
|
||||
uint32_t _sunriseMinutes = 0;
|
||||
uint32_t _sunsetMinutes = 0;
|
||||
|
||||
bool _isValidInfo = false;
|
||||
bool _doRecalc = true;
|
||||
std::mutex _recalcLock;
|
||||
std::atomic_bool _doRecalc = true;
|
||||
uint32_t _lastSunPositionCalculatedYMD = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -5,14 +5,15 @@
|
||||
#include <memory>
|
||||
|
||||
#include "VeDirectMpptController.h"
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class VictronMpptClass {
|
||||
public:
|
||||
VictronMpptClass() = default;
|
||||
~VictronMpptClass() = default;
|
||||
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
void updateSettings();
|
||||
|
||||
bool isDataValid() const;
|
||||
|
||||
@ -35,11 +36,14 @@ public:
|
||||
double getYieldDay() const;
|
||||
|
||||
private:
|
||||
void loop();
|
||||
VictronMpptClass(VictronMpptClass const& other) = delete;
|
||||
VictronMpptClass(VictronMpptClass&& other) = delete;
|
||||
VictronMpptClass& operator=(VictronMpptClass const& other) = delete;
|
||||
VictronMpptClass& operator=(VictronMpptClass&& other) = delete;
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
mutable std::mutex _mutex;
|
||||
using controller_t = std::unique_ptr<VeDirectMpptController>;
|
||||
std::vector<controller_t> _controllers;
|
||||
|
||||
@ -30,12 +30,12 @@
|
||||
#include "WebApi_Huawei.h"
|
||||
#include "WebApi_ws_battery.h"
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiClass {
|
||||
public:
|
||||
WebApiClass();
|
||||
void init();
|
||||
void loop();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
static bool checkCredentials(AsyncWebServerRequest* request);
|
||||
static bool checkCredentialsReadonly(AsyncWebServerRequest* request);
|
||||
@ -43,8 +43,11 @@ public:
|
||||
static void sendTooManyRequests(AsyncWebServerRequest* request);
|
||||
|
||||
private:
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
AsyncWebServer _server;
|
||||
AsyncEventSource _events;
|
||||
|
||||
WebApiBatteryClass _webApiBattery;
|
||||
WebApiConfigClass _webApiConfig;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
class WebApiHuaweiClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void getJsonData(JsonObject& root);
|
||||
private:
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
class WebApiBatteryClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiConfigClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiDeviceClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiDevInfoClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiDtuClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -56,6 +56,7 @@ enum WebApiError {
|
||||
MqttPublishInterval,
|
||||
MqttHassTopicLength,
|
||||
MqttHassTopicCharacter,
|
||||
MqttLwtQos,
|
||||
|
||||
NetworkBase = 8000,
|
||||
NetworkIpInvalid,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiEventlogClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiFirmwareClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,11 +5,12 @@
|
||||
|
||||
class WebApiGridProfileClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
void onGridProfileStatus(AsyncWebServerRequest* request);
|
||||
void onGridProfileRawdata(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiInverterClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiLimitClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiMaintenanceClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
class WebApiMqttClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiNetworkClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiNtpClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiPowerClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
class WebApiPowerLimiterClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
class WebApiPowerMeterClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -7,15 +7,15 @@
|
||||
|
||||
class WebApiPrometheusClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
void onPrometheusMetricsGet(AsyncWebServerRequest* request);
|
||||
|
||||
void addField(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, const char* metricName, const char* channelName = NULL);
|
||||
void addField(AsyncResponseStream* stream, const String& serial, const uint8_t idx, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId, const char* metricName, const char* channelName = nullptr);
|
||||
|
||||
void addPanelInfo(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel);
|
||||
void addPanelInfo(AsyncResponseStream* stream, const String& serial, const uint8_t idx, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiSecurityClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiSysstatusClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
class WebApiVedirectClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
class WebApiWebappClass {
|
||||
public:
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
class WebApiWsHuaweiLiveClass {
|
||||
public:
|
||||
WebApiWsHuaweiLiveClass();
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
class WebApiWsBatteryLiveClass {
|
||||
public:
|
||||
WebApiWsBatteryLiveClass();
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -6,12 +6,10 @@
|
||||
class WebApiWsConsoleClass {
|
||||
public:
|
||||
WebApiWsConsoleClass();
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
AsyncWebSocket _ws;
|
||||
|
||||
|
||||
@ -8,13 +8,13 @@
|
||||
class WebApiWsLiveClass {
|
||||
public:
|
||||
WebApiWsLiveClass();
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
void generateJsonResponse(JsonVariant& root);
|
||||
void addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, String topic = "");
|
||||
void addTotalField(JsonObject& root, String name, float value, String unit, uint8_t digits);
|
||||
void addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId, String topic = "");
|
||||
void addTotalField(JsonObject& root, const String& name, const float value, const String& unit, const uint8_t digits);
|
||||
void onLivedataStatus(AsyncWebServerRequest* request);
|
||||
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
class WebApiWsVedirectLiveClass {
|
||||
public:
|
||||
WebApiWsVedirectLiveClass();
|
||||
void init(AsyncWebServer* server);
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
|
||||
@ -75,6 +75,7 @@
|
||||
#define MQTT_LWT_TOPIC "dtu/status"
|
||||
#define MQTT_LWT_ONLINE "online"
|
||||
#define MQTT_LWT_OFFLINE "offline"
|
||||
#define MQTT_LWT_QOS 2U
|
||||
#define MQTT_PUBLISH_INTERVAL 5U
|
||||
#define MQTT_CLEAN_SESSION true
|
||||
|
||||
@ -97,6 +98,7 @@
|
||||
#define DISPLAY_ROTATION 2U
|
||||
#define DISPLAY_CONTRAST 60U
|
||||
#define DISPLAY_LANGUAGE 0U
|
||||
#define DISPLAY_DIAGRAM_DURATION (10UL * 60UL * 60UL)
|
||||
|
||||
#define REACHABLE_THRESHOLD 2U
|
||||
|
||||
@ -146,3 +148,7 @@
|
||||
#define HUAWEI_AUTO_POWER_UPPER_POWER_LIMIT 2000
|
||||
|
||||
#define VERBOSE_LOGGING true
|
||||
|
||||
#define LED_BRIGHTNESS 100U
|
||||
|
||||
#define MAX_INVERTER_LIMIT 2250
|
||||
3
lib/Frozen/AUTHORS
Normal file
3
lib/Frozen/AUTHORS
Normal file
@ -0,0 +1,3 @@
|
||||
serge-sans-paille <sguelton@quarkslab.com>
|
||||
Jérôme Dumesnil <jerome.dumesnil@gmail.com>
|
||||
Chris Beck <chbeck@tesla.com>
|
||||
202
lib/Frozen/LICENSE
Normal file
202
lib/Frozen/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 Quarkslab
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
245
lib/Frozen/README.rst
Normal file
245
lib/Frozen/README.rst
Normal file
@ -0,0 +1,245 @@
|
||||
Frozen
|
||||
######
|
||||
|
||||
.. image:: https://travis-ci.org/serge-sans-paille/frozen.svg?branch=master
|
||||
:target: https://travis-ci.org/serge-sans-paille/frozen
|
||||
|
||||
Header-only library that provides 0 cost initialization for immutable containers, fixed-size containers, and various algorithms.
|
||||
|
||||
Frozen provides:
|
||||
|
||||
- immutable (a.k.a. frozen), ``constexpr``-compatible versions of ``std::set``,
|
||||
``std::unordered_set``, ``std::map`` and ``std::unordered_map``.
|
||||
|
||||
- fixed-capacity, ``constinit``-compatible versions of ``std::map`` and
|
||||
``std::unordered_map`` with immutable, compile-time selected keys mapped
|
||||
to mutable values.
|
||||
|
||||
- 0-cost initialization version of ``std::search`` for frozen needles using
|
||||
Boyer-Moore or Knuth-Morris-Pratt algorithms.
|
||||
|
||||
|
||||
The ``unordered_*`` containers are guaranteed *perfect* (a.k.a. no hash
|
||||
collision) and the extra storage is linear with respect to the number of keys.
|
||||
|
||||
Once initialized, the container keys cannot be updated, and in exchange, lookups
|
||||
are faster. And initialization is free when ``constexpr`` or ``constinit`` is
|
||||
used :-).
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Just copy the ``include/frozen`` directory somewhere and points to it using the ``-I`` flag. Alternatively, using CMake:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
> mkdir build
|
||||
> cd build
|
||||
> cmake -D CMAKE_BUILD_TYPE=Release ..
|
||||
> make install
|
||||
|
||||
|
||||
Installation via CMake populates configuration files into the ``/usr/local/share``
|
||||
directory which can be consumed by CMake's ``find_package`` instrinsic function.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
A C++ compiler that supports C++14. Clang version 5 is a good pick, GCC version
|
||||
6 lags behind in terms of ``constexpr`` compilation time (At least on my
|
||||
setup), but compiles correctly. Visual Studio 2017 also works correctly!
|
||||
|
||||
Note that gcc 5 isn't supported. (Here's an `old compat branch`_ where a small amount of stuff was ported.)
|
||||
|
||||
.. _old compat branch: https://github.com/cbeck88/frozen/tree/gcc5-support
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Compiled with ``-std=c++14`` flag:
|
||||
|
||||
.. code:: C++
|
||||
|
||||
#include <frozen/set.h>
|
||||
|
||||
constexpr frozen::set<int, 4> some_ints = {1,2,3,5};
|
||||
|
||||
constexpr bool letitgo = some_ints.count(8);
|
||||
|
||||
extern int n;
|
||||
bool letitgoooooo = some_ints.count(n);
|
||||
|
||||
|
||||
As the constructor and some methods are ``constexpr``, it's also possible to write weird stuff like:
|
||||
|
||||
.. code:: C++
|
||||
|
||||
#include <frozen/set.h>
|
||||
|
||||
template<std::size_t N>
|
||||
std::enable_if_t< frozen::set<int, 3>{{1,11,111}}.count(N), int> foo();
|
||||
|
||||
String support is built-in:
|
||||
|
||||
.. code:: C++
|
||||
|
||||
#include <frozen/unordered_map.h>
|
||||
#include <frozen/string.h>
|
||||
|
||||
constexpr frozen::unordered_map<frozen::string, int, 2> olaf = {
|
||||
{"19", 19},
|
||||
{"31", 31},
|
||||
};
|
||||
constexpr auto val = olaf.at("19");
|
||||
|
||||
The associative containers have different functionality with and without ``constexpr``.
|
||||
With ``constexpr``, frozen maps have immutable keys and values. Without ``constexpr``, the
|
||||
values can be updated in runtime (the keys, however, remain immutable):
|
||||
|
||||
.. code:: C++
|
||||
|
||||
|
||||
#include <frozen/unordered_map.h>
|
||||
#include <frozen/string.h>
|
||||
|
||||
static constinit frozen::unordered_map<frozen::string, frozen::string, 2> voice = {
|
||||
{"Anna", "???"},
|
||||
{"Elsa", "???"}
|
||||
};
|
||||
|
||||
int main() {
|
||||
voice.at("Anna") = "Kristen";
|
||||
voice.at("Elsa") = "Idina";
|
||||
}
|
||||
|
||||
You may also prefer a slightly more DRY initialization syntax:
|
||||
|
||||
.. code:: C++
|
||||
|
||||
#include <frozen/set.h>
|
||||
|
||||
constexpr auto some_ints = frozen::make_set<int>({1,2,3,5});
|
||||
|
||||
There are similar ``make_X`` functions for all frozen containers.
|
||||
|
||||
Exception Handling
|
||||
------------------
|
||||
|
||||
For compatibility with STL's API, Frozen may eventually throw exceptions, as in
|
||||
``frozen::map::at``. If you build your code without exception support, or
|
||||
define the ``FROZEN_NO_EXCEPTIONS`` macro variable, they will be turned into an
|
||||
``std::abort``.
|
||||
|
||||
Extending
|
||||
---------
|
||||
|
||||
Just like the regular C++14 container, you can specialize the hash function,
|
||||
the key equality comparator for ``unordered_*`` containers, and the comparison
|
||||
functions for the ordered version.
|
||||
|
||||
It's also possible to specialize the ``frozen::elsa`` structure used for
|
||||
hashing. Note that unlike `std::hash`, the hasher also takes a seed in addition
|
||||
to the value being hashed.
|
||||
|
||||
.. code:: C++
|
||||
|
||||
template <class T> struct elsa {
|
||||
// in case of collisions, different seeds are tried
|
||||
constexpr std::size_t operator()(T const &value, std::size_t seed) const;
|
||||
};
|
||||
|
||||
Ideally, the hash function should have nice statistical properties like *pairwise-independence*:
|
||||
|
||||
If ``x`` and ``y`` are different values, the chance that ``elsa<T>{}(x, seed) == elsa<T>{}(y, seed)``
|
||||
should be very low for a random value of ``seed``.
|
||||
|
||||
Note that frozen always ultimately produces a perfect hash function, and you will always have ``O(1)``
|
||||
lookup with frozen. It's just that if the input hasher performs poorly, the search will take longer and
|
||||
your project will take longer to compile.
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
If you hit a message like this:
|
||||
|
||||
.. code:: none
|
||||
|
||||
[...]
|
||||
note: constexpr evaluation hit maximum step limit; possible infinite loop?
|
||||
|
||||
Then either you've got a very big container and you should increase Clang's
|
||||
thresholds, using ``-fconstexpr-steps=1000000000`` for instance, or the hash
|
||||
functions used by frozen do not suit your data, and you should change them, as
|
||||
in the following:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
struct olaf {
|
||||
constexpr std::size_t operator()(frozen::string const &value, std::size_t seed) const { return seed ^ value[0];}
|
||||
};
|
||||
|
||||
constexpr frozen::unordered_set<frozen::string, 2, olaf/*custom hash*/> hans = { "a", "b" };
|
||||
|
||||
Tests and Benchmarks
|
||||
--------------------
|
||||
|
||||
Using hand-written Makefiles crafted with love and care:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
> # running tests
|
||||
> make -C tests check
|
||||
> # running benchmarks
|
||||
> make -C benchmarks GOOGLE_BENCHMARK_PREFIX=<GOOGLE-BENCHMARK_INSTALL_DIR>
|
||||
|
||||
Using CMake to generate a static configuration build system:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
> mkdir build
|
||||
> cd build
|
||||
> cmake -D CMAKE_BUILD_TYPE=Release \
|
||||
-D frozen.benchmark=ON \
|
||||
-G <"Unix Makefiles" or "Ninja"> ..
|
||||
> # building the tests and benchmarks...
|
||||
> make # ... with make
|
||||
> ninja # ... with ninja
|
||||
> cmake --build . # ... with cmake
|
||||
> # running the tests...
|
||||
> make test # ... with make
|
||||
> ninja test # ... with ninja
|
||||
> cmake --build . --target test # ... with cmake
|
||||
> ctest # ... with ctest
|
||||
> # running the benchmarks...
|
||||
> make benchmark # ... with make
|
||||
> ninja benchmark # ... with ninja
|
||||
> cmake --build . --target benchmark # ... with cmake
|
||||
|
||||
Using CMake to generate an IDE build system with test and benchmark targets
|
||||
|
||||
.. code:: sh
|
||||
|
||||
> mkdir build
|
||||
> cd build
|
||||
> cmake -D frozen.benchmark=ON -G <"Xcode" or "Visual Studio 15 2017"> ..
|
||||
> # using cmake to drive the IDE build, test, and benchmark
|
||||
> cmake --build . --config Release
|
||||
> cmake --build . --target test
|
||||
> cmake --build . --target benchmark
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
The perfect hashing is strongly inspired by the blog post `Throw away the keys:
|
||||
Easy, Minimal Perfect Hashing <http://stevehanov.ca/blog/index.php?id=119>`_.
|
||||
|
||||
Thanks a lot to Jérôme Dumesnil for his high-quality reviews, and to Chris Beck
|
||||
for his contributions on perfect hashing.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
Serge sans Paille ``<serge.guelton@telecom-bretagne.eu>``
|
||||
|
||||
12
lib/Frozen/frozen/CMakeLists.txt
Normal file
12
lib/Frozen/frozen/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
target_sources(frozen-headers INTERFACE
|
||||
"${prefix}/frozen/algorithm.h"
|
||||
"${prefix}/frozen/map.h"
|
||||
"${prefix}/frozen/random.h"
|
||||
"${prefix}/frozen/set.h"
|
||||
"${prefix}/frozen/string.h"
|
||||
"${prefix}/frozen/unordered_map.h"
|
||||
"${prefix}/frozen/unordered_set.h"
|
||||
"${prefix}/frozen/bits/algorithms.h"
|
||||
"${prefix}/frozen/bits/basic_types.h"
|
||||
"${prefix}/frozen/bits/elsa.h"
|
||||
"${prefix}/frozen/bits/pmh.h")
|
||||
198
lib/Frozen/frozen/algorithm.h
Normal file
198
lib/Frozen/frozen/algorithm.h
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_ALGORITHM_H
|
||||
#define FROZEN_LETITGO_ALGORITHM_H
|
||||
|
||||
#include "frozen/bits/basic_types.h"
|
||||
#include "frozen/bits/version.h"
|
||||
#include "frozen/string.h"
|
||||
|
||||
namespace frozen {
|
||||
|
||||
// 'search' implementation if C++17 is not available
|
||||
// https://en.cppreference.com/w/cpp/algorithm/search
|
||||
template<class ForwardIterator, class Searcher>
|
||||
ForwardIterator search(ForwardIterator first, ForwardIterator last, const Searcher & searcher)
|
||||
{
|
||||
return searcher(first, last).first;
|
||||
}
|
||||
|
||||
// text book implementation from
|
||||
// https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
|
||||
|
||||
template <std::size_t size> class knuth_morris_pratt_searcher {
|
||||
bits::carray<std::ptrdiff_t, size> step_;
|
||||
bits::carray<char, size> needle_;
|
||||
|
||||
static constexpr bits::carray<std::ptrdiff_t, size>
|
||||
build_kmp_cache(char const (&needle)[size + 1]) {
|
||||
std::ptrdiff_t cnd = 0;
|
||||
bits::carray<std::ptrdiff_t, size> cache(-1);
|
||||
for (std::size_t pos = 1; pos < size; ++pos) {
|
||||
if (needle[pos] == needle[cnd]) {
|
||||
cache[pos] = cache[cnd];
|
||||
cnd += 1;
|
||||
} else {
|
||||
cache[pos] = cnd;
|
||||
cnd = cache[cnd];
|
||||
while (cnd >= 0 && needle[pos] != needle[cnd])
|
||||
cnd = cache[cnd];
|
||||
cnd += 1;
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr knuth_morris_pratt_searcher(char const (&needle)[size + 1])
|
||||
: step_{build_kmp_cache(needle)}, needle_(needle) {}
|
||||
|
||||
template <class ForwardIterator>
|
||||
constexpr std::pair<ForwardIterator, ForwardIterator> operator()(ForwardIterator first, ForwardIterator last) const {
|
||||
std::size_t i = 0;
|
||||
ForwardIterator iter = first;
|
||||
while (iter != last) {
|
||||
if (needle_[i] == *iter) {
|
||||
if (i == (size - 1))
|
||||
return { iter - i, iter - i + size };
|
||||
++i;
|
||||
++iter;
|
||||
} else {
|
||||
if (step_[i] > -1) {
|
||||
i = step_[i];
|
||||
} else {
|
||||
++iter;
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { last, last };
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr knuth_morris_pratt_searcher<N - 1> make_knuth_morris_pratt_searcher(char const (&needle)[N]) {
|
||||
return {needle};
|
||||
}
|
||||
|
||||
// text book implementation from
|
||||
// https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm
|
||||
|
||||
template <std::size_t size> class boyer_moore_searcher {
|
||||
using skip_table_type = bits::carray<std::ptrdiff_t, sizeof(char) << 8>;
|
||||
using suffix_table_type = bits::carray<std::ptrdiff_t, size>;
|
||||
|
||||
skip_table_type skip_table_;
|
||||
suffix_table_type suffix_table_;
|
||||
bits::carray<char, size> needle_;
|
||||
|
||||
constexpr auto build_skip_table(char const (&needle)[size + 1]) {
|
||||
skip_table_type skip_table(size);
|
||||
for (std::size_t i = 0; i < size - 1; ++i)
|
||||
skip_table[needle[i]] -= i + 1;
|
||||
return skip_table;
|
||||
}
|
||||
|
||||
constexpr bool is_prefix(char const (&needle)[size + 1], std::size_t pos) {
|
||||
std::size_t suffixlen = size - pos;
|
||||
|
||||
for (std::size_t i = 0; i < suffixlen; i++) {
|
||||
if (needle[i] != needle[pos + i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr std::size_t suffix_length(char const (&needle)[size + 1],
|
||||
std::size_t pos) {
|
||||
// increment suffix length slen to the first mismatch or beginning
|
||||
// of the word
|
||||
for (std::size_t slen = 0; slen < pos ; slen++)
|
||||
if (needle[pos - slen] != needle[size - 1 - slen])
|
||||
return slen;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
constexpr auto build_suffix_table(char const (&needle)[size + 1]) {
|
||||
suffix_table_type suffix;
|
||||
std::ptrdiff_t last_prefix_index = size - 1;
|
||||
|
||||
// first loop
|
||||
for (std::ptrdiff_t p = size - 1; p >= 0; p--) {
|
||||
if (is_prefix(needle, p + 1))
|
||||
last_prefix_index = p + 1;
|
||||
|
||||
suffix[p] = last_prefix_index + (size - 1 - p);
|
||||
}
|
||||
|
||||
// second loop
|
||||
for (std::size_t p = 0; p < size - 1; p++) {
|
||||
auto slen = suffix_length(needle, p);
|
||||
if (needle[p - slen] != needle[size - 1 - slen])
|
||||
suffix[size - 1 - slen] = size - 1 - p + slen;
|
||||
|
||||
}
|
||||
return suffix;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr boyer_moore_searcher(char const (&needle)[size + 1])
|
||||
: skip_table_{build_skip_table(needle)},
|
||||
suffix_table_{build_suffix_table(needle)},
|
||||
needle_(needle) {}
|
||||
|
||||
template <class RandomAccessIterator>
|
||||
constexpr std::pair<RandomAccessIterator, RandomAccessIterator> operator()(RandomAccessIterator first, RandomAccessIterator last) const {
|
||||
if (size == 0)
|
||||
return { first, first };
|
||||
|
||||
if (size > size_t(last - first))
|
||||
return { last, last };
|
||||
|
||||
RandomAccessIterator iter = first + size - 1;
|
||||
while (true) {
|
||||
std::ptrdiff_t j = size - 1;
|
||||
while (j > 0 && (*iter == needle_[j])) {
|
||||
--iter;
|
||||
--j;
|
||||
}
|
||||
if (j == 0 && *iter == needle_[0])
|
||||
return { iter, iter + size};
|
||||
|
||||
std::ptrdiff_t jump = std::max(skip_table_[*iter], suffix_table_[j]);
|
||||
if (jump >= last - iter)
|
||||
return { last, last };
|
||||
iter += jump;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr boyer_moore_searcher<N - 1> make_boyer_moore_searcher(char const (&needle)[N]) {
|
||||
return {needle};
|
||||
}
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
235
lib/Frozen/frozen/bits/algorithms.h
Normal file
235
lib/Frozen/frozen/bits/algorithms.h
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_BITS_ALGORITHMS_H
|
||||
#define FROZEN_LETITGO_BITS_ALGORITHMS_H
|
||||
|
||||
#include "frozen/bits/basic_types.h"
|
||||
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
namespace bits {
|
||||
|
||||
auto constexpr next_highest_power_of_two(std::size_t v) {
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
constexpr auto trip_count = std::numeric_limits<decltype(v)>::digits;
|
||||
v--;
|
||||
for(std::size_t i = 1; i < trip_count; i <<= 1)
|
||||
v |= v >> i;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto constexpr log(T v) {
|
||||
std::size_t n = 0;
|
||||
while (v > 1) {
|
||||
n += 1;
|
||||
v >>= 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
constexpr std::size_t bit_weight(std::size_t n) {
|
||||
return (n <= 8*sizeof(unsigned int))
|
||||
+ (n <= 8*sizeof(unsigned long))
|
||||
+ (n <= 8*sizeof(unsigned long long))
|
||||
+ (n <= 128);
|
||||
}
|
||||
|
||||
unsigned int select_uint_least(std::integral_constant<std::size_t, 4>);
|
||||
unsigned long select_uint_least(std::integral_constant<std::size_t, 3>);
|
||||
unsigned long long select_uint_least(std::integral_constant<std::size_t, 2>);
|
||||
template<std::size_t N>
|
||||
unsigned long long select_uint_least(std::integral_constant<std::size_t, N>) {
|
||||
static_assert(N < 2, "unsupported type size");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
template<std::size_t N>
|
||||
using select_uint_least_t = decltype(select_uint_least(std::integral_constant<std::size_t, bit_weight(N)>()));
|
||||
|
||||
template <typename Iter, typename Compare>
|
||||
constexpr auto min_element(Iter begin, const Iter end,
|
||||
Compare const &compare) {
|
||||
auto result = begin;
|
||||
while (begin != end) {
|
||||
if (compare(*begin, *result)) {
|
||||
result = begin;
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr void cswap(T &a, T &b) {
|
||||
auto tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
constexpr void cswap(std::pair<T, U> & a, std::pair<T, U> & b) {
|
||||
cswap(a.first, b.first);
|
||||
cswap(a.second, b.second);
|
||||
}
|
||||
|
||||
template <class... Tys, std::size_t... Is>
|
||||
constexpr void cswap(std::tuple<Tys...> &a, std::tuple<Tys...> &b, std::index_sequence<Is...>) {
|
||||
using swallow = int[];
|
||||
(void) swallow{(cswap(std::get<Is>(a), std::get<Is>(b)), 0)...};
|
||||
}
|
||||
|
||||
template <class... Tys>
|
||||
constexpr void cswap(std::tuple<Tys...> &a, std::tuple<Tys...> &b) {
|
||||
cswap(a, b, std::make_index_sequence<sizeof...(Tys)>());
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
constexpr void iter_swap(Iter a, Iter b) {
|
||||
cswap(*a, *b);
|
||||
}
|
||||
|
||||
template <typename Iterator, class Compare>
|
||||
constexpr Iterator partition(Iterator left, Iterator right, Compare const &compare) {
|
||||
auto pivot = left + (right - left) / 2;
|
||||
iter_swap(right, pivot);
|
||||
pivot = right;
|
||||
for (auto it = left; 0 < right - it; ++it) {
|
||||
if (compare(*it, *pivot)) {
|
||||
iter_swap(it, left);
|
||||
left++;
|
||||
}
|
||||
}
|
||||
iter_swap(pivot, left);
|
||||
pivot = left;
|
||||
return pivot;
|
||||
}
|
||||
|
||||
template <typename Iterator, class Compare>
|
||||
constexpr void quicksort(Iterator left, Iterator right, Compare const &compare) {
|
||||
while (0 < right - left) {
|
||||
auto new_pivot = bits::partition(left, right, compare);
|
||||
quicksort(left, new_pivot, compare);
|
||||
left = new_pivot + 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Container, class Compare>
|
||||
constexpr Container quicksort(Container const &array,
|
||||
Compare const &compare) {
|
||||
Container res = array;
|
||||
quicksort(res.begin(), res.end() - 1, compare);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class T, class Compare> struct LowerBound {
|
||||
T const &value_;
|
||||
Compare const &compare_;
|
||||
constexpr LowerBound(T const &value, Compare const &compare)
|
||||
: value_(value), compare_(compare) {}
|
||||
|
||||
template <class ForwardIt>
|
||||
inline constexpr ForwardIt doit_fast(ForwardIt first,
|
||||
std::integral_constant<std::size_t, 0>) {
|
||||
return first;
|
||||
}
|
||||
|
||||
template <class ForwardIt, std::size_t N>
|
||||
inline constexpr ForwardIt doit_fast(ForwardIt first,
|
||||
std::integral_constant<std::size_t, N>) {
|
||||
auto constexpr step = N / 2;
|
||||
static_assert(N/2 == N - N / 2 - 1, "power of two minus 1");
|
||||
auto it = first + step;
|
||||
auto next_it = compare_(*it, value_) ? it + 1 : first;
|
||||
return doit_fast(next_it, std::integral_constant<std::size_t, N / 2>{});
|
||||
}
|
||||
|
||||
template <class ForwardIt, std::size_t N>
|
||||
inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, N>, std::integral_constant<bool, true>) {
|
||||
return doit_fast(first, std::integral_constant<std::size_t, N>{});
|
||||
}
|
||||
|
||||
template <class ForwardIt, std::size_t N>
|
||||
inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, N>, std::integral_constant<bool, false>) {
|
||||
auto constexpr next_power = next_highest_power_of_two(N);
|
||||
auto constexpr next_start = next_power / 2 - 1;
|
||||
auto it = first + next_start;
|
||||
if (compare_(*it, value_)) {
|
||||
auto constexpr next = N - next_start - 1;
|
||||
return doitfirst(it + 1, std::integral_constant<std::size_t, next>{}, std::integral_constant<bool, next_highest_power_of_two(next) - 1 == next>{});
|
||||
}
|
||||
else
|
||||
return doit_fast(first, std::integral_constant<std::size_t, next_start>{});
|
||||
}
|
||||
|
||||
template <class ForwardIt>
|
||||
inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, 1>, std::integral_constant<bool, false>) {
|
||||
return doit_fast(first, std::integral_constant<std::size_t, 1>{});
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N, class ForwardIt, class T, class Compare>
|
||||
constexpr ForwardIt lower_bound(ForwardIt first, const T &value, Compare const &compare) {
|
||||
return LowerBound<T, Compare>{value, compare}.doitfirst(first, std::integral_constant<std::size_t, N>{}, std::integral_constant<bool, next_highest_power_of_two(N) - 1 == N>{});
|
||||
}
|
||||
|
||||
template <std::size_t N, class Compare, class ForwardIt, class T>
|
||||
constexpr bool binary_search(ForwardIt first, const T &value,
|
||||
Compare const &compare) {
|
||||
ForwardIt where = lower_bound<N>(first, value, compare);
|
||||
return (!(where == first + N) && !(compare(value, *where)));
|
||||
}
|
||||
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
|
||||
{
|
||||
for (; first1 != last1; ++first1, ++first2) {
|
||||
if (!(*first1 == *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
constexpr bool lexicographical_compare(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
|
||||
{
|
||||
for (; (first1 != last1) && (first2 != last2); ++first1, ++first2) {
|
||||
if (*first1 < *first2)
|
||||
return true;
|
||||
if (*first2 < *first1)
|
||||
return false;
|
||||
}
|
||||
return (first1 == last1) && (first2 != last2);
|
||||
}
|
||||
|
||||
} // namespace bits
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
198
lib/Frozen/frozen/bits/basic_types.h
Normal file
198
lib/Frozen/frozen/bits/basic_types.h
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_BASIC_TYPES_H
|
||||
#define FROZEN_LETITGO_BASIC_TYPES_H
|
||||
|
||||
#include "frozen/bits/exceptions.h"
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
namespace bits {
|
||||
|
||||
// used as a fake argument for frozen::make_set and frozen::make_map in the case of N=0
|
||||
struct ignored_arg {};
|
||||
|
||||
template <class T, std::size_t N>
|
||||
class cvector {
|
||||
T data [N] = {}; // zero-initialization for scalar type T, default-initialized otherwise
|
||||
std::size_t dsize = 0;
|
||||
|
||||
public:
|
||||
// Container typdefs
|
||||
using value_type = T;
|
||||
using reference = value_type &;
|
||||
using const_reference = const value_type &;
|
||||
using pointer = value_type *;
|
||||
using const_pointer = const value_type *;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
// Constructors
|
||||
constexpr cvector(void) = default;
|
||||
constexpr cvector(size_type count, const T& value) : dsize(count) {
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
data[i] = value;
|
||||
}
|
||||
|
||||
// Iterators
|
||||
constexpr iterator begin() noexcept { return data; }
|
||||
constexpr iterator end() noexcept { return data + dsize; }
|
||||
constexpr const_iterator begin() const noexcept { return data; }
|
||||
constexpr const_iterator end() const noexcept { return data + dsize; }
|
||||
|
||||
// Capacity
|
||||
constexpr size_type size() const { return dsize; }
|
||||
|
||||
// Element access
|
||||
constexpr reference operator[](std::size_t index) { return data[index]; }
|
||||
constexpr const_reference operator[](std::size_t index) const { return data[index]; }
|
||||
|
||||
constexpr reference back() { return data[dsize - 1]; }
|
||||
constexpr const_reference back() const { return data[dsize - 1]; }
|
||||
|
||||
// Modifiers
|
||||
constexpr void push_back(const T & a) { data[dsize++] = a; }
|
||||
constexpr void push_back(T && a) { data[dsize++] = std::move(a); }
|
||||
constexpr void pop_back() { --dsize; }
|
||||
|
||||
constexpr void clear() { dsize = 0; }
|
||||
};
|
||||
|
||||
template <class T, std::size_t N>
|
||||
class carray {
|
||||
T data_ [N] = {}; // zero-initialization for scalar type T, default-initialized otherwise
|
||||
|
||||
template <class Iter, std::size_t... I>
|
||||
constexpr carray(Iter iter, std::index_sequence<I...>)
|
||||
: data_{((void)I, *iter++)...} {}
|
||||
template <std::size_t... I>
|
||||
constexpr carray(const T& value, std::index_sequence<I...>)
|
||||
: data_{((void)I, value)...} {}
|
||||
|
||||
public:
|
||||
// Container typdefs
|
||||
using value_type = T;
|
||||
using reference = value_type &;
|
||||
using const_reference = const value_type &;
|
||||
using pointer = value_type *;
|
||||
using const_pointer = const value_type *;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
// Constructors
|
||||
constexpr carray() = default;
|
||||
constexpr carray(const value_type& val)
|
||||
: carray(val, std::make_index_sequence<N>()) {}
|
||||
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value, std::size_t> M>
|
||||
constexpr carray(U const (&init)[M])
|
||||
: carray(init, std::make_index_sequence<N>())
|
||||
{
|
||||
static_assert(M >= N, "Cannot initialize a carray with an smaller array");
|
||||
}
|
||||
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value, std::size_t> M>
|
||||
constexpr carray(std::array<U, M> const &init)
|
||||
: carray(init.begin(), std::make_index_sequence<N>())
|
||||
{
|
||||
static_assert(M >= N, "Cannot initialize a carray with an smaller array");
|
||||
}
|
||||
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value>* = nullptr>
|
||||
constexpr carray(std::initializer_list<U> init)
|
||||
: carray(init.begin(), std::make_index_sequence<N>())
|
||||
{
|
||||
// clang & gcc doesn't recognize init.size() as a constexpr
|
||||
// static_assert(init.size() >= N, "Cannot initialize a carray with an smaller initializer list");
|
||||
}
|
||||
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value>* = nullptr>
|
||||
constexpr carray(const carray<U, N>& rhs)
|
||||
: carray(rhs.begin(), std::make_index_sequence<N>())
|
||||
{
|
||||
}
|
||||
|
||||
// Iterators
|
||||
constexpr iterator begin() noexcept { return data_; }
|
||||
constexpr const_iterator begin() const noexcept { return data_; }
|
||||
constexpr iterator end() noexcept { return data_ + N; }
|
||||
constexpr const_iterator end() const noexcept { return data_ + N; }
|
||||
|
||||
// Capacity
|
||||
constexpr size_type size() const { return N; }
|
||||
constexpr size_type max_size() const { return N; }
|
||||
|
||||
// Element access
|
||||
constexpr reference operator[](std::size_t index) { return data_[index]; }
|
||||
constexpr const_reference operator[](std::size_t index) const { return data_[index]; }
|
||||
|
||||
constexpr reference at(std::size_t index) {
|
||||
if (index > N)
|
||||
FROZEN_THROW_OR_ABORT(std::out_of_range("Index (" + std::to_string(index) + ") out of bound (" + std::to_string(N) + ')'));
|
||||
return data_[index];
|
||||
}
|
||||
constexpr const_reference at(std::size_t index) const {
|
||||
if (index > N)
|
||||
FROZEN_THROW_OR_ABORT(std::out_of_range("Index (" + std::to_string(index) + ") out of bound (" + std::to_string(N) + ')'));
|
||||
return data_[index];
|
||||
}
|
||||
|
||||
constexpr reference front() { return data_[0]; }
|
||||
constexpr const_reference front() const { return data_[0]; }
|
||||
|
||||
constexpr reference back() { return data_[N - 1]; }
|
||||
constexpr const_reference back() const { return data_[N - 1]; }
|
||||
|
||||
constexpr value_type* data() noexcept { return data_; }
|
||||
constexpr const value_type* data() const noexcept { return data_; }
|
||||
};
|
||||
template <class T>
|
||||
class carray<T, 0> {
|
||||
|
||||
public:
|
||||
// Container typdefs
|
||||
using value_type = T;
|
||||
using reference = value_type &;
|
||||
using const_reference = const value_type &;
|
||||
using pointer = value_type *;
|
||||
using const_pointer = const value_type *;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
// Constructors
|
||||
constexpr carray(void) = default;
|
||||
|
||||
};
|
||||
|
||||
} // namespace bits
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
40
lib/Frozen/frozen/bits/constexpr_assert.h
Normal file
40
lib/Frozen/frozen/bits/constexpr_assert.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_CONSTEXPR_ASSERT_H
|
||||
#define FROZEN_LETITGO_CONSTEXPR_ASSERT_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// FIXME: find a way to implement that correctly for msvc
|
||||
#define constexpr_assert(cond, msg)
|
||||
|
||||
#else
|
||||
|
||||
#define constexpr_assert(cond, msg)\
|
||||
assert(cond && msg);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
66
lib/Frozen/frozen/bits/defines.h
Normal file
66
lib/Frozen/frozen/bits/defines.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_DEFINES_H
|
||||
#define FROZEN_LETITGO_DEFINES_H
|
||||
|
||||
#if defined(_MSVC_LANG) && !(defined(__EDG__) && defined(__clang__)) // TRANSITION, VSO#273681
|
||||
#define FROZEN_LETITGO_IS_MSVC
|
||||
#endif
|
||||
|
||||
// Code taken from https://stackoverflow.com/questions/43639122/which-values-can-msvc-lang-have
|
||||
#if defined(FROZEN_LETITGO_IS_MSVC)
|
||||
#if _MSVC_LANG > 201402
|
||||
#define FROZEN_LETITGO_HAS_CXX17 1
|
||||
#else /* _MSVC_LANG > 201402 */
|
||||
#define FROZEN_LETITGO_HAS_CXX17 0
|
||||
#endif /* _MSVC_LANG > 201402 */
|
||||
#else /* _MSVC_LANG etc. */
|
||||
#if __cplusplus > 201402
|
||||
#define FROZEN_LETITGO_HAS_CXX17 1
|
||||
#else /* __cplusplus > 201402 */
|
||||
#define FROZEN_LETITGO_HAS_CXX17 0
|
||||
#endif /* __cplusplus > 201402 */
|
||||
#endif /* _MSVC_LANG etc. */
|
||||
// End if taken code
|
||||
|
||||
#if FROZEN_LETITGO_HAS_CXX17 == 1 && defined(FROZEN_LETITGO_IS_MSVC)
|
||||
#define FROZEN_LETITGO_HAS_STRING_VIEW // We assume Visual Studio always has string_view in C++17
|
||||
#else
|
||||
#if FROZEN_LETITGO_HAS_CXX17 == 1 && __has_include(<string_view>)
|
||||
#define FROZEN_LETITGO_HAS_STRING_VIEW
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
#define FROZEN_LETITGO_HAS_CHAR8T
|
||||
#endif
|
||||
|
||||
#if __cpp_deduction_guides >= 201703L
|
||||
#define FROZEN_LETITGO_HAS_DEDUCTION_GUIDES
|
||||
#endif
|
||||
|
||||
#if __cpp_lib_constexpr_string >= 201907L
|
||||
#define FROZEN_LETITGO_HAS_CONSTEXPR_STRING
|
||||
#endif
|
||||
|
||||
#endif // FROZEN_LETITGO_DEFINES_H
|
||||
57
lib/Frozen/frozen/bits/elsa.h
Normal file
57
lib/Frozen/frozen/bits/elsa.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_ELSA_H
|
||||
#define FROZEN_LETITGO_ELSA_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
template <class T = void> struct elsa {
|
||||
static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
|
||||
"only supports integral types, specialize for other types");
|
||||
|
||||
constexpr std::size_t operator()(T const &value, std::size_t seed) const {
|
||||
std::size_t key = seed ^ static_cast<std::size_t>(value);
|
||||
key = (~key) + (key << 21); // key = (key << 21) - key - 1;
|
||||
key = key ^ (key >> 24);
|
||||
key = (key + (key << 3)) + (key << 8); // key * 265
|
||||
key = key ^ (key >> 14);
|
||||
key = (key + (key << 2)) + (key << 4); // key * 21
|
||||
key = key ^ (key >> 28);
|
||||
key = key + (key << 31);
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct elsa<void> {
|
||||
template<class T>
|
||||
constexpr std::size_t operator()(T const &value, std::size_t seed) const {
|
||||
return elsa<T>{}(value, seed);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T=void> using anna = elsa<T>;
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
41
lib/Frozen/frozen/bits/elsa_std.h
Normal file
41
lib/Frozen/frozen/bits/elsa_std.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef FROZEN_LETITGO_BITS_ELSA_STD_H
|
||||
#define FROZEN_LETITGO_BITS_ELSA_STD_H
|
||||
|
||||
#include "defines.h"
|
||||
#include "elsa.h"
|
||||
#include "hash_string.h"
|
||||
|
||||
#ifdef FROZEN_LETITGO_HAS_STRING_VIEW
|
||||
#include <string_view>
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
#ifdef FROZEN_LETITGO_HAS_STRING_VIEW
|
||||
|
||||
template <typename CharT> struct elsa<std::basic_string_view<CharT>>
|
||||
{
|
||||
constexpr std::size_t operator()(const std::basic_string_view<CharT>& value) const {
|
||||
return hash_string(value);
|
||||
}
|
||||
constexpr std::size_t operator()(const std::basic_string_view<CharT>& value, std::size_t seed) const {
|
||||
return hash_string(value, seed);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <typename CharT> struct elsa<std::basic_string<CharT>>
|
||||
{
|
||||
constexpr std::size_t operator()(const std::basic_string<CharT>& value) const {
|
||||
return hash_string(value);
|
||||
}
|
||||
constexpr std::size_t operator()(const std::basic_string<CharT>& value, std::size_t seed) const {
|
||||
return hash_string(value, seed);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif // FROZEN_LETITGO_BITS_ELSA_STD_H
|
||||
39
lib/Frozen/frozen/bits/exceptions.h
Normal file
39
lib/Frozen/frozen/bits/exceptions.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_EXCEPTIONS_H
|
||||
#define FROZEN_LETITGO_EXCEPTIONS_H
|
||||
|
||||
#if defined(FROZEN_NO_EXCEPTIONS) || (defined(_MSC_VER) && !defined(_CPPUNWIND)) || (!defined(_MSC_VER) && !defined(__cpp_exceptions))
|
||||
|
||||
#include <cstdlib>
|
||||
#define FROZEN_THROW_OR_ABORT(_) std::abort()
|
||||
|
||||
#else
|
||||
|
||||
#include <stdexcept>
|
||||
#define FROZEN_THROW_OR_ABORT(err) throw err
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
28
lib/Frozen/frozen/bits/hash_string.h
Normal file
28
lib/Frozen/frozen/bits/hash_string.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef FROZEN_LETITGO_BITS_HASH_STRING_H
|
||||
#define FROZEN_LETITGO_BITS_HASH_STRING_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
template <typename String>
|
||||
constexpr std::size_t hash_string(const String& value) {
|
||||
std::size_t d = 5381;
|
||||
for (const auto& c : value)
|
||||
d = d * 33 + static_cast<std::size_t>(c);
|
||||
return d;
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||
// With the lowest bits removed, based on experimental setup.
|
||||
template <typename String>
|
||||
constexpr std::size_t hash_string(const String& value, std::size_t seed) {
|
||||
std::size_t d = (0x811c9dc5 ^ seed) * static_cast<std::size_t>(0x01000193);
|
||||
for (const auto& c : value)
|
||||
d = (d ^ static_cast<std::size_t>(c)) * static_cast<std::size_t>(0x01000193);
|
||||
return d >> 8 ;
|
||||
}
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif // FROZEN_LETITGO_BITS_HASH_STRING_H
|
||||
56
lib/Frozen/frozen/bits/mpl.h
Normal file
56
lib/Frozen/frozen/bits/mpl.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2022 Giel van Schijndel
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_BITS_MPL_H
|
||||
#define FROZEN_LETITGO_BITS_MPL_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
namespace bits {
|
||||
|
||||
// Forward declarations
|
||||
template <class, std::size_t>
|
||||
class carray;
|
||||
|
||||
template <typename T>
|
||||
struct remove_cv : std::remove_cv<T> {};
|
||||
|
||||
template <typename... T>
|
||||
struct remove_cv<std::pair<T...>> {
|
||||
using type = std::pair<typename remove_cv<T>::type...>;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct remove_cv<carray<T, N>> {
|
||||
using type = carray<typename remove_cv<T>::type, N>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_cv_t = typename remove_cv<T>::type;
|
||||
|
||||
} // namespace bits
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
254
lib/Frozen/frozen/bits/pmh.h
Normal file
254
lib/Frozen/frozen/bits/pmh.h
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
// inspired from http://stevehanov.ca/blog/index.php?id=119
|
||||
#ifndef FROZEN_LETITGO_PMH_H
|
||||
#define FROZEN_LETITGO_PMH_H
|
||||
|
||||
#include "frozen/bits/algorithms.h"
|
||||
#include "frozen/bits/basic_types.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
namespace bits {
|
||||
|
||||
// Function object for sorting buckets in decreasing order of size
|
||||
struct bucket_size_compare {
|
||||
template <typename B>
|
||||
bool constexpr operator()(B const &b0,
|
||||
B const &b1) const {
|
||||
return b0.size() > b1.size();
|
||||
}
|
||||
};
|
||||
|
||||
// Step One in pmh routine is to take all items and hash them into buckets,
|
||||
// with some collisions. Then process those buckets further to build a perfect
|
||||
// hash function.
|
||||
// pmh_buckets represents the initial placement into buckets.
|
||||
|
||||
template <std::size_t M>
|
||||
struct pmh_buckets {
|
||||
// Step 0: Bucket max is 2 * sqrt M
|
||||
// TODO: Come up with justification for this, should it not be O(log M)?
|
||||
static constexpr auto bucket_max = 2 * (1u << (log(M) / 2));
|
||||
|
||||
using bucket_t = cvector<std::size_t, bucket_max>;
|
||||
carray<bucket_t, M> buckets;
|
||||
std::uint64_t seed;
|
||||
|
||||
// Represents a reference to a bucket. This is used because the buckets
|
||||
// have to be sorted, but buckets are big, making it slower than sorting refs
|
||||
struct bucket_ref {
|
||||
unsigned hash;
|
||||
const bucket_t * ptr;
|
||||
|
||||
// Forward some interface of bucket
|
||||
using value_type = typename bucket_t::value_type;
|
||||
using const_iterator = typename bucket_t::const_iterator;
|
||||
|
||||
constexpr auto size() const { return ptr->size(); }
|
||||
constexpr const auto & operator[](std::size_t idx) const { return (*ptr)[idx]; }
|
||||
constexpr auto begin() const { return ptr->begin(); }
|
||||
constexpr auto end() const { return ptr->end(); }
|
||||
};
|
||||
|
||||
// Make a bucket_ref for each bucket
|
||||
template <std::size_t... Is>
|
||||
carray<bucket_ref, M> constexpr make_bucket_refs(std::index_sequence<Is...>) const {
|
||||
return {{ bucket_ref{Is, &buckets[Is]}... }};
|
||||
}
|
||||
|
||||
// Makes a bucket_ref for each bucket and sorts them by size
|
||||
carray<bucket_ref, M> constexpr get_sorted_buckets() const {
|
||||
carray<bucket_ref, M> result{this->make_bucket_refs(std::make_index_sequence<M>())};
|
||||
bits::quicksort(result.begin(), result.end() - 1, bucket_size_compare{});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t M, class Item, std::size_t N, class Hash, class Key, class PRG>
|
||||
pmh_buckets<M> constexpr make_pmh_buckets(const carray<Item, N> & items,
|
||||
Hash const & hash,
|
||||
Key const & key,
|
||||
PRG & prg) {
|
||||
using result_t = pmh_buckets<M>;
|
||||
// Continue until all items are placed without exceeding bucket_max
|
||||
while (1) {
|
||||
result_t result{};
|
||||
result.seed = prg();
|
||||
bool rejected = false;
|
||||
for (std::size_t i = 0; i < items.size(); ++i) {
|
||||
auto & bucket = result.buckets[hash(key(items[i]), static_cast<std::size_t>(result.seed)) % M];
|
||||
if (bucket.size() >= result_t::bucket_max) {
|
||||
rejected = true;
|
||||
break;
|
||||
}
|
||||
bucket.push_back(i);
|
||||
}
|
||||
if (!rejected) { return result; }
|
||||
}
|
||||
}
|
||||
|
||||
// Check if an item appears in a cvector
|
||||
template<class T, std::size_t N>
|
||||
constexpr bool all_different_from(cvector<T, N> & data, T & a) {
|
||||
for (std::size_t i = 0; i < data.size(); ++i)
|
||||
if (data[i] == a)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Represents either an index to a data item array, or a seed to be used with
|
||||
// a hasher. Seed must have high bit of 1, value has high bit of zero.
|
||||
struct seed_or_index {
|
||||
using value_type = std::uint64_t;
|
||||
|
||||
private:
|
||||
static constexpr value_type MINUS_ONE = std::numeric_limits<value_type>::max();
|
||||
static constexpr value_type HIGH_BIT = ~(MINUS_ONE >> 1);
|
||||
|
||||
value_type value_ = 0;
|
||||
|
||||
public:
|
||||
constexpr value_type value() const { return value_; }
|
||||
constexpr bool is_seed() const { return value_ & HIGH_BIT; }
|
||||
|
||||
constexpr seed_or_index(bool is_seed, value_type value)
|
||||
: value_(is_seed ? (value | HIGH_BIT) : (value & ~HIGH_BIT)) {}
|
||||
|
||||
constexpr seed_or_index() = default;
|
||||
constexpr seed_or_index(const seed_or_index &) = default;
|
||||
constexpr seed_or_index & operator =(const seed_or_index &) = default;
|
||||
};
|
||||
|
||||
// Represents the perfect hash function created by pmh algorithm
|
||||
template <std::size_t M, class Hasher>
|
||||
struct pmh_tables : private Hasher {
|
||||
std::uint64_t first_seed_;
|
||||
carray<seed_or_index, M> first_table_;
|
||||
carray<std::size_t, M> second_table_;
|
||||
|
||||
constexpr pmh_tables(
|
||||
std::uint64_t first_seed,
|
||||
carray<seed_or_index, M> first_table,
|
||||
carray<std::size_t, M> second_table,
|
||||
Hasher hash) noexcept
|
||||
: Hasher(hash)
|
||||
, first_seed_(first_seed)
|
||||
, first_table_(first_table)
|
||||
, second_table_(second_table)
|
||||
{}
|
||||
|
||||
constexpr Hasher const& hash_function() const noexcept {
|
||||
return static_cast<Hasher const&>(*this);
|
||||
}
|
||||
|
||||
template <typename KeyType>
|
||||
constexpr std::size_t lookup(const KeyType & key) const {
|
||||
return lookup(key, hash_function());
|
||||
}
|
||||
|
||||
// Looks up a given key, to find its expected index in carray<Item, N>
|
||||
// Always returns a valid index, must use KeyEqual test after to confirm.
|
||||
template <typename KeyType, typename HasherType>
|
||||
constexpr std::size_t lookup(const KeyType & key, const HasherType& hasher) const {
|
||||
auto const d = first_table_[hasher(key, static_cast<std::size_t>(first_seed_)) % M];
|
||||
if (!d.is_seed()) { return static_cast<std::size_t>(d.value()); } // this is narrowing std::uint64 -> std::size_t but should be fine
|
||||
else { return second_table_[hasher(key, static_cast<std::size_t>(d.value())) % M]; }
|
||||
}
|
||||
};
|
||||
|
||||
// Make pmh tables for given items, hash function, prg, etc.
|
||||
template <std::size_t M, class Item, std::size_t N, class Hash, class Key, class PRG>
|
||||
pmh_tables<M, Hash> constexpr make_pmh_tables(const carray<Item, N> &
|
||||
items,
|
||||
Hash const &hash,
|
||||
Key const &key,
|
||||
PRG prg) {
|
||||
// Step 1: Place all of the keys into buckets
|
||||
auto step_one = make_pmh_buckets<M>(items, hash, key, prg);
|
||||
|
||||
// Step 2: Sort the buckets to process the ones with the most items first.
|
||||
auto buckets = step_one.get_sorted_buckets();
|
||||
|
||||
// Special value for unused slots. This is purposefully the index
|
||||
// one-past-the-end of 'items' to function as a sentinel value. Both to avoid
|
||||
// the need to apply the KeyEqual predicate and to be easily convertible to
|
||||
// end().
|
||||
// Unused entries in both hash tables (G and H) have to contain this value.
|
||||
const auto UNUSED = items.size();
|
||||
|
||||
// G becomes the first hash table in the resulting pmh function
|
||||
carray<seed_or_index, M> G({false, UNUSED});
|
||||
|
||||
// H becomes the second hash table in the resulting pmh function
|
||||
carray<std::size_t, M> H(UNUSED);
|
||||
|
||||
// Step 3: Map the items in buckets into hash tables.
|
||||
for (const auto & bucket : buckets) {
|
||||
auto const bsize = bucket.size();
|
||||
|
||||
if (bsize == 1) {
|
||||
// Store index to the (single) item in G
|
||||
// assert(bucket.hash == hash(key(items[bucket[0]]), step_one.seed) % M);
|
||||
G[bucket.hash] = {false, static_cast<std::uint64_t>(bucket[0])};
|
||||
} else if (bsize > 1) {
|
||||
|
||||
// Repeatedly try different H of d until we find a hash function
|
||||
// that places all items in the bucket into free slots
|
||||
seed_or_index d{true, prg()};
|
||||
cvector<std::size_t, decltype(step_one)::bucket_max> bucket_slots;
|
||||
|
||||
while (bucket_slots.size() < bsize) {
|
||||
auto slot = hash(key(items[bucket[bucket_slots.size()]]), static_cast<std::size_t>(d.value())) % M;
|
||||
|
||||
if (H[slot] != UNUSED || !all_different_from(bucket_slots, slot)) {
|
||||
bucket_slots.clear();
|
||||
d = {true, prg()};
|
||||
continue;
|
||||
}
|
||||
|
||||
bucket_slots.push_back(slot);
|
||||
}
|
||||
|
||||
// Put successful seed in G, and put indices to items in their slots
|
||||
// assert(bucket.hash == hash(key(items[bucket[0]]), step_one.seed) % M);
|
||||
G[bucket.hash] = d;
|
||||
for (std::size_t i = 0; i < bsize; ++i)
|
||||
H[bucket_slots[i]] = bucket[i];
|
||||
}
|
||||
}
|
||||
|
||||
return {step_one.seed, G, H, hash};
|
||||
}
|
||||
|
||||
} // namespace bits
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
30
lib/Frozen/frozen/bits/version.h
Normal file
30
lib/Frozen/frozen/bits/version.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_VERSION_H
|
||||
#define FROZEN_LETITGO_VERSION_H
|
||||
|
||||
#define FROZEN_MAJOR_VERSION 1
|
||||
#define FROZEN_MINOR_VERSION 1
|
||||
#define FROZEN_PATCH_VERSION 1
|
||||
|
||||
#endif
|
||||
357
lib/Frozen/frozen/map.h
Normal file
357
lib/Frozen/frozen/map.h
Normal file
@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_MAP_H
|
||||
#define FROZEN_LETITGO_MAP_H
|
||||
|
||||
#include "frozen/bits/algorithms.h"
|
||||
#include "frozen/bits/basic_types.h"
|
||||
#include "frozen/bits/constexpr_assert.h"
|
||||
#include "frozen/bits/exceptions.h"
|
||||
#include "frozen/bits/mpl.h"
|
||||
#include "frozen/bits/version.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
namespace impl {
|
||||
|
||||
template <class Comparator> class CompareKey : private Comparator {
|
||||
public:
|
||||
constexpr Comparator const& key_comp() const noexcept {
|
||||
return static_cast<Comparator const&>(*this);
|
||||
}
|
||||
|
||||
constexpr CompareKey(Comparator const &comparator)
|
||||
: Comparator(comparator) {}
|
||||
|
||||
template <class Key1, class Key2, class Value>
|
||||
constexpr int operator()(std::pair<Key1, Value> const &self,
|
||||
std::pair<Key2, Value> const &other) const {
|
||||
return key_comp()(std::get<0>(self), std::get<0>(other));
|
||||
}
|
||||
|
||||
template <class Key1, class Key2, class Value>
|
||||
constexpr int operator()(Key1 const &self_key,
|
||||
std::pair<Key2, Value> const &other) const {
|
||||
return key_comp()(self_key, std::get<0>(other));
|
||||
}
|
||||
|
||||
template <class Key1, class Key2, class Value>
|
||||
constexpr int operator()(std::pair<Key1, Value> const &self,
|
||||
Key2 const &other_key) const {
|
||||
return key_comp()(std::get<0>(self), other_key);
|
||||
}
|
||||
|
||||
template <class Key1, class Key2>
|
||||
constexpr int operator()(Key1 const &self_key, Key2 const &other_key) const {
|
||||
return key_comp()(self_key, other_key);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
template <class Key, class Value, std::size_t N, class Compare = std::less<Key>>
|
||||
class map : private impl::CompareKey<Compare> {
|
||||
using container_type = bits::carray<std::pair<const Key, Value>, N>;
|
||||
container_type items_;
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
using value_type = typename container_type::value_type;
|
||||
using size_type = typename container_type::size_type;
|
||||
using difference_type = typename container_type::difference_type;
|
||||
using key_compare = Compare;
|
||||
using value_compare = impl::CompareKey<Compare>;
|
||||
using reference = typename container_type::reference;
|
||||
using const_reference = typename container_type::const_reference;
|
||||
using pointer = typename container_type::pointer;
|
||||
using const_pointer = typename container_type::const_pointer;
|
||||
using iterator = typename container_type::iterator;
|
||||
using const_iterator = typename container_type::const_iterator;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
public:
|
||||
/* constructors */
|
||||
constexpr map(container_type items, Compare const &compare)
|
||||
: impl::CompareKey<Compare>{compare}
|
||||
, items_{bits::quicksort(bits::remove_cv_t<container_type>(items), value_comp())} {}
|
||||
|
||||
explicit constexpr map(container_type items)
|
||||
: map{items, Compare{}} {}
|
||||
|
||||
constexpr map(std::initializer_list<value_type> items, Compare const &compare)
|
||||
: map{container_type {items}, compare} {
|
||||
constexpr_assert(items.size() == N, "Inconsistent initializer_list size and type size argument");
|
||||
}
|
||||
|
||||
constexpr map(std::initializer_list<value_type> items)
|
||||
: map{items, Compare{}} {}
|
||||
|
||||
/* element access */
|
||||
constexpr Value const& at(Key const &key) const {
|
||||
return at_impl(*this, key);
|
||||
}
|
||||
constexpr Value& at(Key const &key) {
|
||||
return at_impl(*this, key);
|
||||
}
|
||||
|
||||
/* iterators */
|
||||
constexpr iterator begin() { return items_.begin(); }
|
||||
constexpr const_iterator begin() const { return items_.begin(); }
|
||||
constexpr const_iterator cbegin() const { return items_.begin(); }
|
||||
constexpr iterator end() { return items_.end(); }
|
||||
constexpr const_iterator end() const { return items_.end(); }
|
||||
constexpr const_iterator cend() const { return items_.end(); }
|
||||
|
||||
constexpr reverse_iterator rbegin() { return reverse_iterator{items_.end()}; }
|
||||
constexpr const_reverse_iterator rbegin() const { return const_reverse_iterator{items_.end()}; }
|
||||
constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator{items_.end()}; }
|
||||
constexpr reverse_iterator rend() { return reverse_iterator{items_.begin()}; }
|
||||
constexpr const_reverse_iterator rend() const { return const_reverse_iterator{items_.begin()}; }
|
||||
constexpr const_reverse_iterator crend() const { return const_reverse_iterator{items_.begin()}; }
|
||||
|
||||
/* capacity */
|
||||
constexpr bool empty() const { return !N; }
|
||||
constexpr size_type size() const { return N; }
|
||||
constexpr size_type max_size() const { return N; }
|
||||
|
||||
/* lookup */
|
||||
|
||||
template <class KeyType>
|
||||
constexpr std::size_t count(KeyType const &key) const {
|
||||
return bits::binary_search<N>(items_.begin(), key, value_comp());
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator find(KeyType const &key) const {
|
||||
return map::find_impl(*this, key);
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr iterator find(KeyType const &key) {
|
||||
return map::find_impl(*this, key);
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr bool contains(KeyType const &key) const {
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr std::pair<const_iterator, const_iterator>
|
||||
equal_range(KeyType const &key) const {
|
||||
return equal_range_impl(*this, key);
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr std::pair<iterator, iterator> equal_range(KeyType const &key) {
|
||||
return equal_range_impl(*this, key);
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator lower_bound(KeyType const &key) const {
|
||||
return lower_bound_impl(*this, key);
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr iterator lower_bound(KeyType const &key) {
|
||||
return lower_bound_impl(*this, key);
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator upper_bound(KeyType const &key) const {
|
||||
return upper_bound_impl(*this, key);
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr iterator upper_bound(KeyType const &key) {
|
||||
return upper_bound_impl(*this, key);
|
||||
}
|
||||
|
||||
/* observers */
|
||||
constexpr const key_compare& key_comp() const { return value_comp().key_comp(); }
|
||||
constexpr const value_compare& value_comp() const { return static_cast<impl::CompareKey<Compare> const&>(*this); }
|
||||
|
||||
private:
|
||||
template <class This, class KeyType>
|
||||
static inline constexpr auto& at_impl(This&& self, KeyType const &key) {
|
||||
auto where = self.find(key);
|
||||
if (where != self.end())
|
||||
return where->second;
|
||||
else
|
||||
FROZEN_THROW_OR_ABORT(std::out_of_range("unknown key"));
|
||||
}
|
||||
|
||||
template <class This, class KeyType>
|
||||
static inline constexpr auto find_impl(This&& self, KeyType const &key) {
|
||||
auto where = self.lower_bound(key);
|
||||
if (where != self.end() && !self.value_comp()(key, *where))
|
||||
return where;
|
||||
else
|
||||
return self.end();
|
||||
}
|
||||
|
||||
template <class This, class KeyType>
|
||||
static inline constexpr auto equal_range_impl(This&& self, KeyType const &key) {
|
||||
auto lower = self.lower_bound(key);
|
||||
using lower_t = decltype(lower);
|
||||
if (lower != self.end() && !self.value_comp()(key, *lower))
|
||||
return std::pair<lower_t, lower_t>{lower, lower + 1};
|
||||
else
|
||||
return std::pair<lower_t, lower_t>{lower, lower};
|
||||
}
|
||||
|
||||
template <class This, class KeyType>
|
||||
static inline constexpr auto lower_bound_impl(This&& self, KeyType const &key) -> decltype(self.end()) {
|
||||
return bits::lower_bound<N>(self.items_.begin(), key, self.value_comp());
|
||||
}
|
||||
|
||||
template <class This, class KeyType>
|
||||
static inline constexpr auto upper_bound_impl(This&& self, KeyType const &key) {
|
||||
auto lower = self.lower_bound(key);
|
||||
if (lower != self.end() && !self.value_comp()(key, *lower))
|
||||
return lower + 1;
|
||||
else
|
||||
return lower;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Key, class Value, class Compare>
|
||||
class map<Key, Value, 0, Compare> : private impl::CompareKey<Compare> {
|
||||
using container_type = bits::carray<std::pair<Key, Value>, 0>;
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
using value_type = typename container_type::value_type;
|
||||
using size_type = typename container_type::size_type;
|
||||
using difference_type = typename container_type::difference_type;
|
||||
using key_compare = Compare;
|
||||
using value_compare = impl::CompareKey<Compare>;
|
||||
using reference = typename container_type::reference;
|
||||
using const_reference = typename container_type::const_reference;
|
||||
using pointer = typename container_type::pointer;
|
||||
using const_pointer = typename container_type::const_pointer;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = pointer;
|
||||
using const_reverse_iterator = const_pointer;
|
||||
|
||||
public:
|
||||
/* constructors */
|
||||
constexpr map(const map &other) = default;
|
||||
constexpr map(std::initializer_list<value_type>, Compare const &compare)
|
||||
: impl::CompareKey<Compare>{compare} {}
|
||||
constexpr map(std::initializer_list<value_type> items)
|
||||
: map{items, Compare{}} {}
|
||||
|
||||
/* element access */
|
||||
template <class KeyType>
|
||||
constexpr mapped_type at(KeyType const &) const {
|
||||
FROZEN_THROW_OR_ABORT(std::out_of_range("invalid key"));
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr mapped_type at(KeyType const &) {
|
||||
FROZEN_THROW_OR_ABORT(std::out_of_range("invalid key"));
|
||||
}
|
||||
|
||||
/* iterators */
|
||||
constexpr iterator begin() { return nullptr; }
|
||||
constexpr const_iterator begin() const { return nullptr; }
|
||||
constexpr const_iterator cbegin() const { return nullptr; }
|
||||
constexpr iterator end() { return nullptr; }
|
||||
constexpr const_iterator end() const { return nullptr; }
|
||||
constexpr const_iterator cend() const { return nullptr; }
|
||||
|
||||
constexpr reverse_iterator rbegin() { return nullptr; }
|
||||
constexpr const_reverse_iterator rbegin() const { return nullptr; }
|
||||
constexpr const_reverse_iterator crbegin() const { return nullptr; }
|
||||
constexpr reverse_iterator rend() { return nullptr; }
|
||||
constexpr const_reverse_iterator rend() const { return nullptr; }
|
||||
constexpr const_reverse_iterator crend() const { return nullptr; }
|
||||
|
||||
/* capacity */
|
||||
constexpr bool empty() const { return true; }
|
||||
constexpr size_type size() const { return 0; }
|
||||
constexpr size_type max_size() const { return 0; }
|
||||
|
||||
/* lookup */
|
||||
|
||||
template <class KeyType>
|
||||
constexpr std::size_t count(KeyType const &) const { return 0; }
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator find(KeyType const &) const { return end(); }
|
||||
template <class KeyType>
|
||||
constexpr iterator find(KeyType const &) { return end(); }
|
||||
|
||||
template <class KeyType>
|
||||
constexpr std::pair<const_iterator, const_iterator>
|
||||
equal_range(KeyType const &) const { return {end(), end()}; }
|
||||
template <class KeyType>
|
||||
constexpr std::pair<iterator, iterator>
|
||||
equal_range(KeyType const &) { return {end(), end()}; }
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator lower_bound(KeyType const &) const { return end(); }
|
||||
template <class KeyType>
|
||||
constexpr iterator lower_bound(KeyType const &) { return end(); }
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator upper_bound(KeyType const &) const { return end(); }
|
||||
template <class KeyType>
|
||||
constexpr iterator upper_bound(KeyType const &) { return end(); }
|
||||
|
||||
/* observers */
|
||||
constexpr key_compare const& key_comp() const { return value_comp().key_comp(); }
|
||||
constexpr value_compare const& value_comp() const { return static_cast<impl::CompareKey<Compare> const&>(*this); }
|
||||
};
|
||||
|
||||
template <typename T, typename U, typename Compare = std::less<T>>
|
||||
constexpr auto make_map(bits::ignored_arg = {}/* for consistency with the initializer below for N = 0*/) {
|
||||
return map<T, U, 0, Compare>{};
|
||||
}
|
||||
|
||||
template <typename T, typename U, std::size_t N>
|
||||
constexpr auto make_map(std::pair<T, U> const (&items)[N]) {
|
||||
return map<T, U, N>{items};
|
||||
}
|
||||
|
||||
template <typename T, typename U, std::size_t N>
|
||||
constexpr auto make_map(std::array<std::pair<T, U>, N> const &items) {
|
||||
return map<T, U, N>{items};
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Compare, std::size_t N>
|
||||
constexpr auto make_map(std::pair<T, U> const (&items)[N], Compare const& compare = Compare{}) {
|
||||
return map<T, U, N, Compare>{items, compare};
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Compare, std::size_t N>
|
||||
constexpr auto make_map(std::array<std::pair<T, U>, N> const &items, Compare const& compare = Compare{}) {
|
||||
return map<T, U, N, Compare>{items, compare};
|
||||
}
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
97
lib/Frozen/frozen/random.h
Normal file
97
lib/Frozen/frozen/random.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_RANDOM_H
|
||||
#define FROZEN_LETITGO_RANDOM_H
|
||||
|
||||
#include "frozen/bits/algorithms.h"
|
||||
#include "frozen/bits/version.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace frozen {
|
||||
template <class UIntType, UIntType a, UIntType c, UIntType m>
|
||||
class linear_congruential_engine {
|
||||
|
||||
static_assert(std::is_unsigned<UIntType>::value,
|
||||
"UIntType must be an unsigned integral type");
|
||||
|
||||
template<class T>
|
||||
static constexpr UIntType modulo(T val, std::integral_constant<UIntType, 0>) {
|
||||
return static_cast<UIntType>(val);
|
||||
}
|
||||
|
||||
template<class T, UIntType M>
|
||||
static constexpr UIntType modulo(T val, std::integral_constant<UIntType, M>) {
|
||||
// the static cast below may end up doing a truncation
|
||||
return static_cast<UIntType>(val % M);
|
||||
}
|
||||
|
||||
public:
|
||||
using result_type = UIntType;
|
||||
static constexpr result_type multiplier = a;
|
||||
static constexpr result_type increment = c;
|
||||
static constexpr result_type modulus = m;
|
||||
static constexpr result_type default_seed = 1u;
|
||||
|
||||
linear_congruential_engine() = default;
|
||||
constexpr linear_congruential_engine(result_type s) { seed(s); }
|
||||
|
||||
void seed(result_type s = default_seed) { state_ = s; }
|
||||
constexpr result_type operator()() {
|
||||
using uint_least_t = bits::select_uint_least_t<bits::log(a) + bits::log(m) + 4>;
|
||||
uint_least_t tmp = static_cast<uint_least_t>(multiplier) * state_ + increment;
|
||||
|
||||
state_ = modulo(tmp, std::integral_constant<UIntType, modulus>());
|
||||
return state_;
|
||||
}
|
||||
constexpr void discard(unsigned long long n) {
|
||||
while (n--)
|
||||
operator()();
|
||||
}
|
||||
static constexpr result_type min() { return increment == 0u ? 1u : 0u; }
|
||||
static constexpr result_type max() { return modulus - 1u; }
|
||||
friend constexpr bool operator==(linear_congruential_engine const &self,
|
||||
linear_congruential_engine const &other) {
|
||||
return self.state_ == other.state_;
|
||||
}
|
||||
friend constexpr bool operator!=(linear_congruential_engine const &self,
|
||||
linear_congruential_engine const &other) {
|
||||
return !(self == other);
|
||||
}
|
||||
|
||||
private:
|
||||
result_type state_ = default_seed;
|
||||
};
|
||||
|
||||
using minstd_rand0 =
|
||||
linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647>;
|
||||
using minstd_rand =
|
||||
linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647>;
|
||||
|
||||
// This generator is used by default in unordered frozen containers
|
||||
using default_prg_t = minstd_rand;
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
260
lib/Frozen/frozen/set.h
Normal file
260
lib/Frozen/frozen/set.h
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_SET_H
|
||||
#define FROZEN_SET_H
|
||||
|
||||
#include "frozen/bits/algorithms.h"
|
||||
#include "frozen/bits/basic_types.h"
|
||||
#include "frozen/bits/constexpr_assert.h"
|
||||
#include "frozen/bits/version.h"
|
||||
#include "frozen/bits/defines.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
template <class Key, std::size_t N, class Compare = std::less<Key>> class set : private Compare {
|
||||
using container_type = bits::carray<Key, N>;
|
||||
container_type keys_;
|
||||
|
||||
public:
|
||||
/* container typedefs*/
|
||||
using key_type = Key;
|
||||
using value_type = Key;
|
||||
using size_type = typename container_type::size_type;
|
||||
using difference_type = typename container_type::size_type;
|
||||
using key_compare = Compare;
|
||||
using value_compare = Compare;
|
||||
using reference = typename container_type::const_reference;
|
||||
using const_reference = reference;
|
||||
using pointer = typename container_type::const_pointer;
|
||||
using const_pointer = pointer;
|
||||
using iterator = typename container_type::const_iterator;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_iterator = iterator;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
public:
|
||||
/* constructors */
|
||||
constexpr set(const set &other) = default;
|
||||
|
||||
constexpr set(container_type keys, Compare const & comp)
|
||||
: Compare{comp}
|
||||
, keys_(bits::quicksort(keys, value_comp())) {
|
||||
}
|
||||
|
||||
explicit constexpr set(container_type keys)
|
||||
: set{keys, Compare{}} {}
|
||||
|
||||
constexpr set(std::initializer_list<Key> keys, Compare const & comp)
|
||||
: set{container_type{keys}, comp} {
|
||||
constexpr_assert(keys.size() == N, "Inconsistent initializer_list size and type size argument");
|
||||
}
|
||||
|
||||
constexpr set(std::initializer_list<Key> keys)
|
||||
: set{keys, Compare{}} {}
|
||||
|
||||
constexpr set& operator=(const set &other) = default;
|
||||
|
||||
/* capacity */
|
||||
constexpr bool empty() const { return !N; }
|
||||
constexpr size_type size() const { return N; }
|
||||
constexpr size_type max_size() const { return N; }
|
||||
|
||||
/* lookup */
|
||||
template <class KeyType>
|
||||
constexpr std::size_t count(KeyType const &key) const {
|
||||
return bits::binary_search<N>(keys_.begin(), key, value_comp());
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator find(KeyType const &key) const {
|
||||
const_iterator where = lower_bound(key);
|
||||
if ((where != end()) && !value_comp()(key, *where))
|
||||
return where;
|
||||
else
|
||||
return end();
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr bool contains(KeyType const &key) const {
|
||||
return this->find(key) != keys_.end();
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr std::pair<const_iterator, const_iterator> equal_range(KeyType const &key) const {
|
||||
auto const lower = lower_bound(key);
|
||||
if (lower == end())
|
||||
return {lower, lower};
|
||||
else
|
||||
return {lower, lower + 1};
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator lower_bound(KeyType const &key) const {
|
||||
auto const where = bits::lower_bound<N>(keys_.begin(), key, value_comp());
|
||||
if ((where != end()) && !value_comp()(key, *where))
|
||||
return where;
|
||||
else
|
||||
return end();
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator upper_bound(KeyType const &key) const {
|
||||
auto const where = bits::lower_bound<N>(keys_.begin(), key, value_comp());
|
||||
if ((where != end()) && !value_comp()(key, *where))
|
||||
return where + 1;
|
||||
else
|
||||
return end();
|
||||
}
|
||||
|
||||
/* observers */
|
||||
constexpr const key_compare& key_comp() const { return value_comp(); }
|
||||
constexpr const key_compare& value_comp() const { return static_cast<const Compare&>(*this); }
|
||||
|
||||
/* iterators */
|
||||
constexpr const_iterator begin() const { return keys_.begin(); }
|
||||
constexpr const_iterator cbegin() const { return keys_.begin(); }
|
||||
constexpr const_iterator end() const { return keys_.end(); }
|
||||
constexpr const_iterator cend() const { return keys_.end(); }
|
||||
|
||||
constexpr const_reverse_iterator rbegin() const { return const_reverse_iterator{keys_.end()}; }
|
||||
constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator{keys_.end()}; }
|
||||
constexpr const_reverse_iterator rend() const { return const_reverse_iterator{keys_.begin()}; }
|
||||
constexpr const_reverse_iterator crend() const { return const_reverse_iterator{keys_.begin()}; }
|
||||
|
||||
/* comparison */
|
||||
constexpr bool operator==(set const& rhs) const { return bits::equal(begin(), end(), rhs.begin()); }
|
||||
constexpr bool operator!=(set const& rhs) const { return !(*this == rhs); }
|
||||
constexpr bool operator<(set const& rhs) const { return bits::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end()); }
|
||||
constexpr bool operator<=(set const& rhs) const { return (*this < rhs) || (*this == rhs); }
|
||||
constexpr bool operator>(set const& rhs) const { return bits::lexicographical_compare(rhs.begin(), rhs.end(), begin(), end()); }
|
||||
constexpr bool operator>=(set const& rhs) const { return (*this > rhs) || (*this == rhs); }
|
||||
};
|
||||
|
||||
template <class Key, class Compare> class set<Key, 0, Compare> : private Compare {
|
||||
using container_type = bits::carray<Key, 0>; // just for the type definitions
|
||||
|
||||
public:
|
||||
/* container typedefs*/
|
||||
using key_type = Key;
|
||||
using value_type = Key;
|
||||
using size_type = typename container_type::size_type;
|
||||
using difference_type = typename container_type::size_type;
|
||||
using key_compare = Compare;
|
||||
using value_compare = Compare;
|
||||
using reference = typename container_type::const_reference;
|
||||
using const_reference = reference;
|
||||
using pointer = typename container_type::const_pointer;
|
||||
using const_pointer = pointer;
|
||||
using iterator = pointer;
|
||||
using reverse_iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using const_reverse_iterator = const_pointer;
|
||||
|
||||
public:
|
||||
/* constructors */
|
||||
constexpr set(const set &other) = default;
|
||||
constexpr set(bits::carray<Key, 0>, Compare const &) {}
|
||||
explicit constexpr set(bits::carray<Key, 0>) {}
|
||||
|
||||
constexpr set(std::initializer_list<Key>, Compare const &comp)
|
||||
: Compare{comp} {}
|
||||
constexpr set(std::initializer_list<Key> keys) : set{keys, Compare{}} {}
|
||||
|
||||
constexpr set& operator=(const set &other) = default;
|
||||
|
||||
/* capacity */
|
||||
constexpr bool empty() const { return true; }
|
||||
constexpr size_type size() const { return 0; }
|
||||
constexpr size_type max_size() const { return 0; }
|
||||
|
||||
/* lookup */
|
||||
template <class KeyType>
|
||||
constexpr std::size_t count(KeyType const &) const { return 0; }
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator find(KeyType const &) const { return end(); }
|
||||
|
||||
template <class KeyType>
|
||||
constexpr std::pair<const_iterator, const_iterator>
|
||||
equal_range(KeyType const &) const { return {end(), end()}; }
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator lower_bound(KeyType const &) const { return end(); }
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator upper_bound(KeyType const &) const { return end(); }
|
||||
|
||||
/* observers */
|
||||
constexpr const key_compare& key_comp() const { return value_comp(); }
|
||||
constexpr const key_compare& value_comp() const { return static_cast<Compare const&>(*this); }
|
||||
|
||||
/* iterators */
|
||||
constexpr const_iterator begin() const { return nullptr; }
|
||||
constexpr const_iterator cbegin() const { return nullptr; }
|
||||
constexpr const_iterator end() const { return nullptr; }
|
||||
constexpr const_iterator cend() const { return nullptr; }
|
||||
|
||||
constexpr const_reverse_iterator rbegin() const { return nullptr; }
|
||||
constexpr const_reverse_iterator crbegin() const { return nullptr; }
|
||||
constexpr const_reverse_iterator rend() const { return nullptr; }
|
||||
constexpr const_reverse_iterator crend() const { return nullptr; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr auto make_set(bits::ignored_arg = {}/* for consistency with the initializer below for N = 0*/) {
|
||||
return set<T, 0>{};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
constexpr auto make_set(const T (&args)[N]) {
|
||||
return set<T, N>(args);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
constexpr auto make_set(std::array<T, N> const &args) {
|
||||
return set<T, N>(args);
|
||||
}
|
||||
|
||||
template <typename T, typename Compare, std::size_t N>
|
||||
constexpr auto make_set(const T (&args)[N], Compare const& compare = Compare{}) {
|
||||
return set<T, N, Compare>(args, compare);
|
||||
}
|
||||
|
||||
template <typename T, typename Compare, std::size_t N>
|
||||
constexpr auto make_set(std::array<T, N> const &args, Compare const& compare = Compare{}) {
|
||||
return set<T, N, Compare>(args, compare);
|
||||
}
|
||||
|
||||
#ifdef FROZEN_LETITGO_HAS_DEDUCTION_GUIDES
|
||||
|
||||
template<class T, class... Args>
|
||||
set(T, Args...) -> set<T, sizeof...(Args) + 1>;
|
||||
|
||||
#endif // FROZEN_LETITGO_HAS_DEDUCTION_GUIDES
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
152
lib/Frozen/frozen/string.h
Normal file
152
lib/Frozen/frozen/string.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_STRING_H
|
||||
#define FROZEN_LETITGO_STRING_H
|
||||
|
||||
#include "frozen/bits/elsa.h"
|
||||
#include "frozen/bits/hash_string.h"
|
||||
#include "frozen/bits/version.h"
|
||||
#include "frozen/bits/defines.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
#ifdef FROZEN_LETITGO_HAS_STRING_VIEW
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
namespace frozen {
|
||||
|
||||
template <typename _CharT>
|
||||
class basic_string {
|
||||
using chr_t = _CharT;
|
||||
|
||||
chr_t const *data_;
|
||||
std::size_t size_;
|
||||
|
||||
public:
|
||||
template <std::size_t N>
|
||||
constexpr basic_string(chr_t const (&data)[N])
|
||||
: data_(data), size_(N - 1) {}
|
||||
constexpr basic_string(chr_t const *data, std::size_t size)
|
||||
: data_(data), size_(size) {}
|
||||
|
||||
#ifdef FROZEN_LETITGO_HAS_STRING_VIEW
|
||||
constexpr basic_string(std::basic_string_view<chr_t> data)
|
||||
: data_(data.data()), size_(data.size()) {}
|
||||
#endif
|
||||
|
||||
constexpr basic_string(const basic_string &) noexcept = default;
|
||||
constexpr basic_string &operator=(const basic_string &) noexcept = default;
|
||||
|
||||
constexpr std::size_t size() const { return size_; }
|
||||
|
||||
constexpr chr_t operator[](std::size_t i) const { return data_[i]; }
|
||||
|
||||
constexpr bool operator==(basic_string other) const {
|
||||
if (size_ != other.size_)
|
||||
return false;
|
||||
for (std::size_t i = 0; i < size_; ++i)
|
||||
if (data_[i] != other.data_[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool operator<(const basic_string &other) const {
|
||||
unsigned i = 0;
|
||||
while (i < size() && i < other.size()) {
|
||||
if ((*this)[i] < other[i]) {
|
||||
return true;
|
||||
}
|
||||
if ((*this)[i] > other[i]) {
|
||||
return false;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return size() < other.size();
|
||||
}
|
||||
|
||||
friend constexpr bool operator>(const basic_string& lhs, const basic_string& rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
constexpr const chr_t *data() const { return data_; }
|
||||
constexpr const chr_t *begin() const { return data(); }
|
||||
constexpr const chr_t *end() const { return data() + size(); }
|
||||
};
|
||||
|
||||
template <typename _CharT> struct elsa<basic_string<_CharT>> {
|
||||
constexpr std::size_t operator()(basic_string<_CharT> value) const {
|
||||
return hash_string(value);
|
||||
}
|
||||
constexpr std::size_t operator()(basic_string<_CharT> value, std::size_t seed) const {
|
||||
return hash_string(value, seed);
|
||||
}
|
||||
};
|
||||
|
||||
using string = basic_string<char>;
|
||||
using wstring = basic_string<wchar_t>;
|
||||
using u16string = basic_string<char16_t>;
|
||||
using u32string = basic_string<char32_t>;
|
||||
|
||||
#ifdef FROZEN_LETITGO_HAS_CHAR8T
|
||||
using u8string = basic_string<char8_t>;
|
||||
#endif
|
||||
|
||||
namespace string_literals {
|
||||
|
||||
constexpr string operator"" _s(const char *data, std::size_t size) {
|
||||
return {data, size};
|
||||
}
|
||||
|
||||
constexpr wstring operator"" _s(const wchar_t *data, std::size_t size) {
|
||||
return {data, size};
|
||||
}
|
||||
|
||||
constexpr u16string operator"" _s(const char16_t *data, std::size_t size) {
|
||||
return {data, size};
|
||||
}
|
||||
|
||||
constexpr u32string operator"" _s(const char32_t *data, std::size_t size) {
|
||||
return {data, size};
|
||||
}
|
||||
|
||||
#ifdef FROZEN_LETITGO_HAS_CHAR8T
|
||||
constexpr u8string operator"" _s(const char8_t *data, std::size_t size) {
|
||||
return {data, size};
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace string_literals
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
namespace std {
|
||||
template <typename _CharT> struct hash<frozen::basic_string<_CharT>> {
|
||||
std::size_t operator()(frozen::basic_string<_CharT> s) const {
|
||||
return frozen::elsa<frozen::basic_string<_CharT>>{}(s);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
217
lib/Frozen/frozen/unordered_map.h
Normal file
217
lib/Frozen/frozen/unordered_map.h
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_UNORDERED_MAP_H
|
||||
#define FROZEN_LETITGO_UNORDERED_MAP_H
|
||||
|
||||
#include "frozen/bits/basic_types.h"
|
||||
#include "frozen/bits/constexpr_assert.h"
|
||||
#include "frozen/bits/elsa.h"
|
||||
#include "frozen/bits/exceptions.h"
|
||||
#include "frozen/bits/pmh.h"
|
||||
#include "frozen/bits/version.h"
|
||||
#include "frozen/random.h"
|
||||
|
||||
#include <tuple>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
namespace bits {
|
||||
|
||||
struct GetKey {
|
||||
template <class KV> constexpr auto const &operator()(KV const &kv) const {
|
||||
return kv.first;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace bits
|
||||
|
||||
template <class Key, class Value, std::size_t N, typename Hash = anna<Key>,
|
||||
class KeyEqual = std::equal_to<Key>>
|
||||
class unordered_map : private KeyEqual {
|
||||
static constexpr std::size_t storage_size =
|
||||
bits::next_highest_power_of_two(N) * (N < 32 ? 2 : 1); // size adjustment to prevent high collision rate for small sets
|
||||
using container_type = bits::carray<std::pair<const Key, Value>, N>;
|
||||
using tables_type = bits::pmh_tables<storage_size, Hash>;
|
||||
|
||||
container_type items_;
|
||||
tables_type tables_;
|
||||
|
||||
public:
|
||||
/* typedefs */
|
||||
using Self = unordered_map<Key, Value, N, Hash, KeyEqual>;
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
using value_type = typename container_type::value_type;
|
||||
using size_type = typename container_type::size_type;
|
||||
using difference_type = typename container_type::difference_type;
|
||||
using hasher = Hash;
|
||||
using key_equal = KeyEqual;
|
||||
using reference = typename container_type::reference;
|
||||
using const_reference = typename container_type::const_reference;
|
||||
using pointer = typename container_type::pointer;
|
||||
using const_pointer = typename container_type::const_pointer;
|
||||
using iterator = typename container_type::iterator;
|
||||
using const_iterator = typename container_type::const_iterator;
|
||||
|
||||
public:
|
||||
/* constructors */
|
||||
unordered_map(unordered_map const &) = default;
|
||||
constexpr unordered_map(container_type items,
|
||||
Hash const &hash, KeyEqual const &equal)
|
||||
: KeyEqual{equal}
|
||||
, items_{items}
|
||||
, tables_{
|
||||
bits::make_pmh_tables<storage_size>(
|
||||
items_, hash, bits::GetKey{}, default_prg_t{})} {}
|
||||
explicit constexpr unordered_map(container_type items)
|
||||
: unordered_map{items, Hash{}, KeyEqual{}} {}
|
||||
|
||||
constexpr unordered_map(std::initializer_list<value_type> items,
|
||||
Hash const & hash, KeyEqual const & equal)
|
||||
: unordered_map{container_type{items}, hash, equal} {
|
||||
constexpr_assert(items.size() == N, "Inconsistent initializer_list size and type size argument");
|
||||
}
|
||||
|
||||
constexpr unordered_map(std::initializer_list<value_type> items)
|
||||
: unordered_map{items, Hash{}, KeyEqual{}} {}
|
||||
|
||||
/* iterators */
|
||||
constexpr iterator begin() { return items_.begin(); }
|
||||
constexpr iterator end() { return items_.end(); }
|
||||
constexpr const_iterator begin() const { return items_.begin(); }
|
||||
constexpr const_iterator end() const { return items_.end(); }
|
||||
constexpr const_iterator cbegin() const { return items_.begin(); }
|
||||
constexpr const_iterator cend() const { return items_.end(); }
|
||||
|
||||
/* capacity */
|
||||
constexpr bool empty() const { return !N; }
|
||||
constexpr size_type size() const { return N; }
|
||||
constexpr size_type max_size() const { return N; }
|
||||
|
||||
/* lookup */
|
||||
template <class KeyType>
|
||||
constexpr std::size_t count(KeyType const &key) const {
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr Value const &at(KeyType const &key) const {
|
||||
return at_impl(*this, key);
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr Value &at(KeyType const &key) {
|
||||
return at_impl(*this, key);
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr const_iterator find(KeyType const &key) const {
|
||||
return find_impl(*this, key, hash_function(), key_eq());
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr iterator find(KeyType const &key) {
|
||||
return find_impl(*this, key, hash_function(), key_eq());
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr bool contains(KeyType const &key) const {
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr std::pair<const_iterator, const_iterator> equal_range(KeyType const &key) const {
|
||||
return equal_range_impl(*this, key);
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr std::pair<iterator, iterator> equal_range(KeyType const &key) {
|
||||
return equal_range_impl(*this, key);
|
||||
}
|
||||
|
||||
/* bucket interface */
|
||||
constexpr std::size_t bucket_count() const { return storage_size; }
|
||||
constexpr std::size_t max_bucket_count() const { return storage_size; }
|
||||
|
||||
/* observers*/
|
||||
constexpr const hasher& hash_function() const { return tables_.hash_function(); }
|
||||
constexpr const key_equal& key_eq() const { return static_cast<KeyEqual const&>(*this); }
|
||||
|
||||
private:
|
||||
template <class This, class KeyType>
|
||||
static inline constexpr auto& at_impl(This&& self, KeyType const &key) {
|
||||
auto it = self.find(key);
|
||||
if (it != self.end())
|
||||
return it->second;
|
||||
else
|
||||
FROZEN_THROW_OR_ABORT(std::out_of_range("unknown key"));
|
||||
}
|
||||
|
||||
template <class This, class KeyType, class Hasher, class Equal>
|
||||
static inline constexpr auto find_impl(This&& self, KeyType const &key, Hasher const &hash, Equal const &equal) {
|
||||
auto const pos = self.tables_.lookup(key, hash);
|
||||
auto it = self.items_.begin() + pos;
|
||||
if (it != self.items_.end() && equal(it->first, key))
|
||||
return it;
|
||||
else
|
||||
return self.items_.end();
|
||||
}
|
||||
|
||||
template <class This, class KeyType>
|
||||
static inline constexpr auto equal_range_impl(This&& self, KeyType const &key) {
|
||||
auto const it = self.find(key);
|
||||
if (it != self.end())
|
||||
return std::make_pair(it, it + 1);
|
||||
else
|
||||
return std::make_pair(self.end(), self.end());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U, std::size_t N>
|
||||
constexpr auto make_unordered_map(std::pair<T, U> const (&items)[N]) {
|
||||
return unordered_map<T, U, N>{items};
|
||||
}
|
||||
|
||||
template <typename T, typename U, std::size_t N, typename Hasher, typename Equal>
|
||||
constexpr auto make_unordered_map(
|
||||
std::pair<T, U> const (&items)[N],
|
||||
Hasher const &hash = elsa<T>{},
|
||||
Equal const &equal = std::equal_to<T>{}) {
|
||||
return unordered_map<T, U, N, Hasher, Equal>{items, hash, equal};
|
||||
}
|
||||
|
||||
template <typename T, typename U, std::size_t N>
|
||||
constexpr auto make_unordered_map(std::array<std::pair<T, U>, N> const &items) {
|
||||
return unordered_map<T, U, N>{items};
|
||||
}
|
||||
|
||||
template <typename T, typename U, std::size_t N, typename Hasher, typename Equal>
|
||||
constexpr auto make_unordered_map(
|
||||
std::array<std::pair<T, U>, N> const &items,
|
||||
Hasher const &hash = elsa<T>{},
|
||||
Equal const &equal = std::equal_to<T>{}) {
|
||||
return unordered_map<T, U, N, Hasher, Equal>{items, hash, equal};
|
||||
}
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
181
lib/Frozen/frozen/unordered_set.h
Normal file
181
lib/Frozen/frozen/unordered_set.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Frozen
|
||||
* Copyright 2016 QuarksLab
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef FROZEN_LETITGO_UNORDERED_SET_H
|
||||
#define FROZEN_LETITGO_UNORDERED_SET_H
|
||||
|
||||
#include "frozen/bits/basic_types.h"
|
||||
#include "frozen/bits/constexpr_assert.h"
|
||||
#include "frozen/bits/elsa.h"
|
||||
#include "frozen/bits/pmh.h"
|
||||
#include "frozen/bits/version.h"
|
||||
#include "frozen/random.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace frozen {
|
||||
|
||||
namespace bits {
|
||||
|
||||
struct Get {
|
||||
template <class T> constexpr T const &operator()(T const &key) const {
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace bits
|
||||
|
||||
template <class Key, std::size_t N, typename Hash = elsa<Key>,
|
||||
class KeyEqual = std::equal_to<Key>>
|
||||
class unordered_set : private KeyEqual {
|
||||
static constexpr std::size_t storage_size =
|
||||
bits::next_highest_power_of_two(N) * (N < 32 ? 2 : 1); // size adjustment to prevent high collision rate for small sets
|
||||
using container_type = bits::carray<Key, N>;
|
||||
using tables_type = bits::pmh_tables<storage_size, Hash>;
|
||||
|
||||
container_type keys_;
|
||||
tables_type tables_;
|
||||
|
||||
public:
|
||||
/* typedefs */
|
||||
using key_type = Key;
|
||||
using value_type = Key;
|
||||
using size_type = typename container_type::size_type;
|
||||
using difference_type = typename container_type::difference_type;
|
||||
using hasher = Hash;
|
||||
using key_equal = KeyEqual;
|
||||
using const_reference = typename container_type::const_reference;
|
||||
using reference = const_reference;
|
||||
using const_pointer = typename container_type::const_pointer;
|
||||
using pointer = const_pointer;
|
||||
using const_iterator = typename container_type::const_iterator;
|
||||
using iterator = const_iterator;
|
||||
|
||||
public:
|
||||
/* constructors */
|
||||
unordered_set(unordered_set const &) = default;
|
||||
constexpr unordered_set(container_type keys, Hash const &hash,
|
||||
KeyEqual const &equal)
|
||||
: KeyEqual{equal}
|
||||
, keys_{keys}
|
||||
, tables_{bits::make_pmh_tables<storage_size>(
|
||||
keys_, hash, bits::Get{}, default_prg_t{})} {}
|
||||
explicit constexpr unordered_set(container_type keys)
|
||||
: unordered_set{keys, Hash{}, KeyEqual{}} {}
|
||||
|
||||
constexpr unordered_set(std::initializer_list<Key> keys)
|
||||
: unordered_set{keys, Hash{}, KeyEqual{}} {}
|
||||
|
||||
constexpr unordered_set(std::initializer_list<Key> keys, Hash const & hash, KeyEqual const & equal)
|
||||
: unordered_set{container_type{keys}, hash, equal} {
|
||||
constexpr_assert(keys.size() == N, "Inconsistent initializer_list size and type size argument");
|
||||
}
|
||||
|
||||
/* iterators */
|
||||
constexpr const_iterator begin() const { return keys_.begin(); }
|
||||
constexpr const_iterator end() const { return keys_.end(); }
|
||||
constexpr const_iterator cbegin() const { return keys_.begin(); }
|
||||
constexpr const_iterator cend() const { return keys_.end(); }
|
||||
|
||||
/* capacity */
|
||||
constexpr bool empty() const { return !N; }
|
||||
constexpr size_type size() const { return N; }
|
||||
constexpr size_type max_size() const { return N; }
|
||||
|
||||
/* lookup */
|
||||
template <class KeyType>
|
||||
constexpr std::size_t count(KeyType const &key) const {
|
||||
return find(key, hash_function(), key_eq()) != end();
|
||||
}
|
||||
|
||||
template <class KeyType, class Hasher, class Equal>
|
||||
constexpr const_iterator find(KeyType const &key, Hasher const &hash, Equal const &equal) const {
|
||||
auto const pos = tables_.lookup(key, hash);
|
||||
auto it = keys_.begin() + pos;
|
||||
if (it != keys_.end() && equal(*it, key))
|
||||
return it;
|
||||
else
|
||||
return keys_.end();
|
||||
}
|
||||
template <class KeyType>
|
||||
constexpr const_iterator find(KeyType const &key) const {
|
||||
auto const pos = tables_.lookup(key, hash_function());
|
||||
auto it = keys_.begin() + pos;
|
||||
if (it != keys_.end() && key_eq()(*it, key))
|
||||
return it;
|
||||
else
|
||||
return keys_.end();
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr bool contains(KeyType const &key) const {
|
||||
return this->find(key) != keys_.end();
|
||||
}
|
||||
|
||||
template <class KeyType>
|
||||
constexpr std::pair<const_iterator, const_iterator> equal_range(KeyType const &key) const {
|
||||
auto const it = find(key);
|
||||
if (it != end())
|
||||
return {it, it + 1};
|
||||
else
|
||||
return {keys_.end(), keys_.end()};
|
||||
}
|
||||
|
||||
/* bucket interface */
|
||||
constexpr std::size_t bucket_count() const { return storage_size; }
|
||||
constexpr std::size_t max_bucket_count() const { return storage_size; }
|
||||
|
||||
/* observers*/
|
||||
constexpr const hasher& hash_function() const { return tables_.hash_function(); }
|
||||
constexpr const key_equal& key_eq() const { return static_cast<KeyEqual const&>(*this); }
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
constexpr auto make_unordered_set(T const (&keys)[N]) {
|
||||
return unordered_set<T, N>{keys};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, typename Hasher, typename Equal>
|
||||
constexpr auto make_unordered_set(T const (&keys)[N], Hasher const& hash, Equal const& equal) {
|
||||
return unordered_set<T, N, Hasher, Equal>{keys, hash, equal};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
constexpr auto make_unordered_set(std::array<T, N> const &keys) {
|
||||
return unordered_set<T, N>{keys};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, typename Hasher, typename Equal>
|
||||
constexpr auto make_unordered_set(std::array<T, N> const &keys, Hasher const& hash, Equal const& equal) {
|
||||
return unordered_set<T, N, Hasher, Equal>{keys, hash, equal};
|
||||
}
|
||||
|
||||
#ifdef FROZEN_LETITGO_HAS_DEDUCTION_GUIDES
|
||||
|
||||
template <class T, class... Args>
|
||||
unordered_set(T, Args...) -> unordered_set<T, sizeof...(Args) + 1>;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace frozen
|
||||
|
||||
#endif
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
*/
|
||||
#include "Hoymiles.h"
|
||||
#include "Utils.h"
|
||||
@ -24,12 +24,12 @@ void HoymilesClass::init()
|
||||
_radioCmt.reset(new HoymilesRadio_CMT());
|
||||
}
|
||||
|
||||
void HoymilesClass::initNRF(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ)
|
||||
void HoymilesClass::initNRF(SPIClass* initialisedSpiBus, const uint8_t pinCE, const uint8_t pinIRQ)
|
||||
{
|
||||
_radioNrf->init(initialisedSpiBus, pinCE, pinIRQ);
|
||||
}
|
||||
|
||||
void HoymilesClass::initCMT(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio2, int8_t pin_gpio3)
|
||||
void HoymilesClass::initCMT(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const int8_t pin_gpio2, const int8_t pin_gpio3)
|
||||
{
|
||||
_radioCmt->init(pin_sdio, pin_clk, pin_cs, pin_fcs, pin_gpio2, pin_gpio3);
|
||||
}
|
||||
@ -40,110 +40,114 @@ void HoymilesClass::loop()
|
||||
_radioNrf->loop();
|
||||
_radioCmt->loop();
|
||||
|
||||
if (getNumInverters() > 0) {
|
||||
if (millis() - _lastPoll > (_pollInterval * 1000)) {
|
||||
static uint8_t inverterPos = 0;
|
||||
if (getNumInverters() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<InverterAbstract> iv = getInverterByPos(inverterPos);
|
||||
if ((iv == nullptr) || ((iv != nullptr) && (!iv->getRadio()->isInitialized()))) {
|
||||
if (++inverterPos >= getNumInverters()) {
|
||||
inverterPos = 0;
|
||||
}
|
||||
if (millis() - _lastPoll > (_pollInterval * 1000)) {
|
||||
static uint8_t inverterPos = 0;
|
||||
|
||||
std::shared_ptr<InverterAbstract> iv = getInverterByPos(inverterPos);
|
||||
if ((iv == nullptr) || ((iv != nullptr) && (!iv->getRadio()->isInitialized()))) {
|
||||
if (++inverterPos >= getNumInverters()) {
|
||||
inverterPos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (iv != nullptr && iv->getRadio()->isInitialized() && iv->getRadio()->isQueueEmpty()) {
|
||||
|
||||
if (iv->getZeroValuesIfUnreachable() && !iv->isReachable()) {
|
||||
iv->Statistics()->zeroRuntimeData();
|
||||
}
|
||||
|
||||
if (iv != nullptr && iv->getRadio()->isInitialized() && iv->getRadio()->isQueueEmpty()) {
|
||||
if (iv->getEnablePolling() || iv->getEnableCommands()) {
|
||||
_messageOutput->print("Fetch inverter: ");
|
||||
_messageOutput->println(iv->serial(), HEX);
|
||||
|
||||
if (iv->getZeroValuesIfUnreachable() && !iv->isReachable()) {
|
||||
Hoymiles.getMessageOutput()->println("Set runtime data to zero");
|
||||
iv->Statistics()->zeroRuntimeData();
|
||||
if (!iv->isReachable()) {
|
||||
iv->sendChangeChannelRequest();
|
||||
}
|
||||
|
||||
if (iv->getEnablePolling() || iv->getEnableCommands()) {
|
||||
_messageOutput->print("Fetch inverter: ");
|
||||
_messageOutput->println(iv->serial(), HEX);
|
||||
iv->sendStatsRequest();
|
||||
|
||||
if (!iv->isReachable()) {
|
||||
iv->sendChangeChannelRequest();
|
||||
}
|
||||
// Fetch event log
|
||||
const bool force = iv->EventLog()->getLastAlarmRequestSuccess() == CMD_NOK;
|
||||
iv->sendAlarmLogRequest(force);
|
||||
|
||||
iv->sendStatsRequest();
|
||||
|
||||
// Fetch event log
|
||||
bool force = iv->EventLog()->getLastAlarmRequestSuccess() == CMD_NOK;
|
||||
iv->sendAlarmLogRequest(force);
|
||||
|
||||
// Fetch limit
|
||||
if (((millis() - iv->SystemConfigPara()->getLastUpdateRequest() > HOY_SYSTEM_CONFIG_PARA_POLL_INTERVAL)
|
||||
&& (millis() - iv->SystemConfigPara()->getLastUpdateCommand() > HOY_SYSTEM_CONFIG_PARA_POLL_MIN_DURATION))) {
|
||||
_messageOutput->println("Request SystemConfigPara");
|
||||
iv->sendSystemConfigParaRequest();
|
||||
}
|
||||
|
||||
// Set limit if required
|
||||
if (iv->SystemConfigPara()->getLastLimitCommandSuccess() == CMD_NOK) {
|
||||
_messageOutput->println("Resend ActivePowerControl");
|
||||
iv->resendActivePowerControlRequest();
|
||||
}
|
||||
|
||||
// Set power status if required
|
||||
if (iv->PowerCommand()->getLastPowerCommandSuccess() == CMD_NOK) {
|
||||
_messageOutput->println("Resend PowerCommand");
|
||||
iv->resendPowerControlRequest();
|
||||
}
|
||||
|
||||
// Fetch dev info (but first fetch stats)
|
||||
if (iv->Statistics()->getLastUpdate() > 0) {
|
||||
bool invalidDevInfo = !iv->DevInfo()->containsValidData()
|
||||
&& iv->DevInfo()->getLastUpdateAll() > 0
|
||||
&& iv->DevInfo()->getLastUpdateSimple() > 0;
|
||||
|
||||
if (invalidDevInfo) {
|
||||
_messageOutput->println("DevInfo: No Valid Data");
|
||||
}
|
||||
|
||||
if ((iv->DevInfo()->getLastUpdateAll() == 0)
|
||||
|| (iv->DevInfo()->getLastUpdateSimple() == 0)
|
||||
|| invalidDevInfo) {
|
||||
_messageOutput->println("Request device info");
|
||||
iv->sendDevInfoRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch grid profile
|
||||
if (iv->Statistics()->getLastUpdate() > 0 && iv->GridProfile()->getLastUpdate() == 0) {
|
||||
iv->sendGridOnProFileParaRequest();
|
||||
}
|
||||
|
||||
_lastPoll = millis();
|
||||
// Fetch limit
|
||||
if (((millis() - iv->SystemConfigPara()->getLastUpdateRequest() > HOY_SYSTEM_CONFIG_PARA_POLL_INTERVAL)
|
||||
&& (millis() - iv->SystemConfigPara()->getLastUpdateCommand() > HOY_SYSTEM_CONFIG_PARA_POLL_MIN_DURATION))) {
|
||||
_messageOutput->println("Request SystemConfigPara");
|
||||
iv->sendSystemConfigParaRequest();
|
||||
}
|
||||
|
||||
if (++inverterPos >= getNumInverters()) {
|
||||
inverterPos = 0;
|
||||
// Set limit if required
|
||||
if (iv->SystemConfigPara()->getLastLimitCommandSuccess() == CMD_NOK) {
|
||||
_messageOutput->println("Resend ActivePowerControl");
|
||||
iv->resendActivePowerControlRequest();
|
||||
}
|
||||
|
||||
// Set power status if required
|
||||
if (iv->PowerCommand()->getLastPowerCommandSuccess() == CMD_NOK) {
|
||||
_messageOutput->println("Resend PowerCommand");
|
||||
iv->resendPowerControlRequest();
|
||||
}
|
||||
|
||||
// Fetch dev info (but first fetch stats)
|
||||
if (iv->Statistics()->getLastUpdate() > 0) {
|
||||
const bool invalidDevInfo = !iv->DevInfo()->containsValidData()
|
||||
&& iv->DevInfo()->getLastUpdateAll() > 0
|
||||
&& iv->DevInfo()->getLastUpdateSimple() > 0;
|
||||
|
||||
if (invalidDevInfo) {
|
||||
_messageOutput->println("DevInfo: No Valid Data");
|
||||
}
|
||||
|
||||
if ((iv->DevInfo()->getLastUpdateAll() == 0)
|
||||
|| (iv->DevInfo()->getLastUpdateSimple() == 0)
|
||||
|| invalidDevInfo) {
|
||||
_messageOutput->println("Request device info");
|
||||
iv->sendDevInfoRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch grid profile
|
||||
if (iv->Statistics()->getLastUpdate() > 0 && iv->GridProfile()->getLastUpdate() == 0) {
|
||||
iv->sendGridOnProFileParaRequest();
|
||||
}
|
||||
|
||||
_lastPoll = millis();
|
||||
}
|
||||
|
||||
// Perform housekeeping of all inverters on day change
|
||||
int8_t currentWeekDay = Utils::getWeekDay();
|
||||
static int8_t lastWeekDay = -1;
|
||||
if (lastWeekDay == -1) {
|
||||
if (++inverterPos >= getNumInverters()) {
|
||||
inverterPos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform housekeeping of all inverters on day change
|
||||
const int8_t currentWeekDay = Utils::getWeekDay();
|
||||
static int8_t lastWeekDay = -1;
|
||||
if (lastWeekDay == -1) {
|
||||
lastWeekDay = currentWeekDay;
|
||||
} else {
|
||||
if (currentWeekDay != lastWeekDay) {
|
||||
|
||||
for (auto& inv : _inverters) {
|
||||
// Have to reset the offets first, otherwise it will
|
||||
// Substract the offset from zero which leads to a high value
|
||||
inv->Statistics()->resetYieldDayCorrection();
|
||||
if (inv->getZeroYieldDayOnMidnight()) {
|
||||
inv->Statistics()->zeroDailyData();
|
||||
}
|
||||
}
|
||||
|
||||
lastWeekDay = currentWeekDay;
|
||||
} else {
|
||||
if (currentWeekDay != lastWeekDay) {
|
||||
|
||||
for (auto& inv : _inverters) {
|
||||
if (inv->getZeroYieldDayOnMidnight()) {
|
||||
inv->Statistics()->zeroDailyData();
|
||||
}
|
||||
}
|
||||
|
||||
lastWeekDay = currentWeekDay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<InverterAbstract> HoymilesClass::addInverter(const char* name, uint64_t serial)
|
||||
std::shared_ptr<InverterAbstract> HoymilesClass::addInverter(const char* name, const uint64_t serial)
|
||||
{
|
||||
std::shared_ptr<InverterAbstract> i = nullptr;
|
||||
if (HMT_4CH::isValidSerial(serial)) {
|
||||
@ -176,7 +180,7 @@ std::shared_ptr<InverterAbstract> HoymilesClass::addInverter(const char* name, u
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<InverterAbstract> HoymilesClass::getInverterByPos(uint8_t pos)
|
||||
std::shared_ptr<InverterAbstract> HoymilesClass::getInverterByPos(const uint8_t pos)
|
||||
{
|
||||
if (pos >= _inverters.size()) {
|
||||
return nullptr;
|
||||
@ -185,7 +189,7 @@ std::shared_ptr<InverterAbstract> HoymilesClass::getInverterByPos(uint8_t pos)
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<InverterAbstract> HoymilesClass::getInverterBySerial(uint64_t serial)
|
||||
std::shared_ptr<InverterAbstract> HoymilesClass::getInverterBySerial(const uint64_t serial)
|
||||
{
|
||||
for (uint8_t i = 0; i < _inverters.size(); i++) {
|
||||
if (_inverters[i]->serial() == serial) {
|
||||
@ -195,9 +199,9 @@ std::shared_ptr<InverterAbstract> HoymilesClass::getInverterBySerial(uint64_t se
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<InverterAbstract> HoymilesClass::getInverterByFragment(fragment_t* fragment)
|
||||
std::shared_ptr<InverterAbstract> HoymilesClass::getInverterByFragment(const fragment_t& fragment)
|
||||
{
|
||||
if (fragment->len <= 4) {
|
||||
if (fragment.len <= 4) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -207,10 +211,10 @@ std::shared_ptr<InverterAbstract> HoymilesClass::getInverterByFragment(fragment_
|
||||
serial_u p;
|
||||
p.u64 = inv->serial();
|
||||
|
||||
if ((p.b[3] == fragment->fragment[1])
|
||||
&& (p.b[2] == fragment->fragment[2])
|
||||
&& (p.b[1] == fragment->fragment[3])
|
||||
&& (p.b[0] == fragment->fragment[4])) {
|
||||
if ((p.b[3] == fragment.fragment[1])
|
||||
&& (p.b[2] == fragment.fragment[2])
|
||||
&& (p.b[1] == fragment.fragment[3])
|
||||
&& (p.b[0] == fragment.fragment[4])) {
|
||||
|
||||
return inv;
|
||||
}
|
||||
@ -218,7 +222,7 @@ std::shared_ptr<InverterAbstract> HoymilesClass::getInverterByFragment(fragment_
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HoymilesClass::removeInverterBySerial(uint64_t serial)
|
||||
void HoymilesClass::removeInverterBySerial(const uint64_t serial)
|
||||
{
|
||||
for (uint8_t i = 0; i < _inverters.size(); i++) {
|
||||
if (_inverters[i]->serial() == serial) {
|
||||
@ -229,7 +233,7 @@ void HoymilesClass::removeInverterBySerial(uint64_t serial)
|
||||
}
|
||||
}
|
||||
|
||||
size_t HoymilesClass::getNumInverters()
|
||||
size_t HoymilesClass::getNumInverters() const
|
||||
{
|
||||
return _inverters.size();
|
||||
}
|
||||
@ -244,17 +248,17 @@ HoymilesRadio_CMT* HoymilesClass::getRadioCmt()
|
||||
return _radioCmt.get();
|
||||
}
|
||||
|
||||
bool HoymilesClass::isAllRadioIdle()
|
||||
bool HoymilesClass::isAllRadioIdle() const
|
||||
{
|
||||
return _radioNrf.get()->isIdle() && _radioCmt.get()->isIdle();
|
||||
}
|
||||
|
||||
uint32_t HoymilesClass::PollInterval()
|
||||
uint32_t HoymilesClass::PollInterval() const
|
||||
{
|
||||
return _pollInterval;
|
||||
}
|
||||
|
||||
void HoymilesClass::setPollInterval(uint32_t interval)
|
||||
void HoymilesClass::setPollInterval(const uint32_t interval)
|
||||
{
|
||||
_pollInterval = interval;
|
||||
}
|
||||
|
||||
@ -16,29 +16,29 @@
|
||||
class HoymilesClass {
|
||||
public:
|
||||
void init();
|
||||
void initNRF(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ);
|
||||
void initCMT(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio2, int8_t pin_gpio3);
|
||||
void initNRF(SPIClass* initialisedSpiBus, const uint8_t pinCE, const uint8_t pinIRQ);
|
||||
void initCMT(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const int8_t pin_gpio2, const int8_t pin_gpio3);
|
||||
void loop();
|
||||
|
||||
void setMessageOutput(Print* output);
|
||||
Print* getMessageOutput();
|
||||
Print* getVerboseMessageOutput();
|
||||
|
||||
std::shared_ptr<InverterAbstract> addInverter(const char* name, uint64_t serial);
|
||||
std::shared_ptr<InverterAbstract> getInverterByPos(uint8_t pos);
|
||||
std::shared_ptr<InverterAbstract> getInverterBySerial(uint64_t serial);
|
||||
std::shared_ptr<InverterAbstract> getInverterByFragment(fragment_t* fragment);
|
||||
void removeInverterBySerial(uint64_t serial);
|
||||
size_t getNumInverters();
|
||||
std::shared_ptr<InverterAbstract> addInverter(const char* name, const uint64_t serial);
|
||||
std::shared_ptr<InverterAbstract> getInverterByPos(const uint8_t pos);
|
||||
std::shared_ptr<InverterAbstract> getInverterBySerial(const uint64_t serial);
|
||||
std::shared_ptr<InverterAbstract> getInverterByFragment(const fragment_t& fragment);
|
||||
void removeInverterBySerial(const uint64_t serial);
|
||||
size_t getNumInverters() const;
|
||||
|
||||
HoymilesRadio_NRF* getRadioNrf();
|
||||
HoymilesRadio_CMT* getRadioCmt();
|
||||
|
||||
uint32_t PollInterval();
|
||||
void setPollInterval(uint32_t interval);
|
||||
uint32_t PollInterval() const;
|
||||
void setPollInterval(const uint32_t interval);
|
||||
void setVerboseLogging(bool verboseLogging);
|
||||
|
||||
bool isAllRadioIdle();
|
||||
bool isAllRadioIdle() const;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<InverterAbstract>> _inverters;
|
||||
|
||||
@ -6,17 +6,17 @@
|
||||
#include "Hoymiles.h"
|
||||
#include "crc.h"
|
||||
|
||||
serial_u HoymilesRadio::DtuSerial()
|
||||
serial_u HoymilesRadio::DtuSerial() const
|
||||
{
|
||||
return _dtuSerial;
|
||||
}
|
||||
|
||||
void HoymilesRadio::setDtuSerial(uint64_t serial)
|
||||
void HoymilesRadio::setDtuSerial(const uint64_t serial)
|
||||
{
|
||||
_dtuSerial.u64 = serial;
|
||||
}
|
||||
|
||||
serial_u HoymilesRadio::convertSerialToRadioId(serial_u serial)
|
||||
serial_u HoymilesRadio::convertSerialToRadioId(const serial_u serial)
|
||||
{
|
||||
serial_u radioId;
|
||||
radioId.u64 = 0;
|
||||
@ -28,27 +28,27 @@ serial_u HoymilesRadio::convertSerialToRadioId(serial_u serial)
|
||||
return radioId;
|
||||
}
|
||||
|
||||
bool HoymilesRadio::checkFragmentCrc(fragment_t* fragment)
|
||||
bool HoymilesRadio::checkFragmentCrc(const fragment_t& fragment) const
|
||||
{
|
||||
uint8_t crc = crc8(fragment->fragment, fragment->len - 1);
|
||||
return (crc == fragment->fragment[fragment->len - 1]);
|
||||
const uint8_t crc = crc8(fragment.fragment, fragment.len - 1);
|
||||
return (crc == fragment.fragment[fragment.len - 1]);
|
||||
}
|
||||
|
||||
void HoymilesRadio::sendRetransmitPacket(uint8_t fragment_id)
|
||||
void HoymilesRadio::sendRetransmitPacket(const uint8_t fragment_id)
|
||||
{
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
|
||||
CommandAbstract* requestCmd = cmd->getRequestFrameCommand(fragment_id);
|
||||
|
||||
if (requestCmd != nullptr) {
|
||||
sendEsbPacket(requestCmd);
|
||||
sendEsbPacket(*requestCmd);
|
||||
}
|
||||
}
|
||||
|
||||
void HoymilesRadio::sendLastPacketAgain()
|
||||
{
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
sendEsbPacket(cmd);
|
||||
sendEsbPacket(*cmd);
|
||||
}
|
||||
|
||||
void HoymilesRadio::handleReceivedPackage()
|
||||
@ -59,7 +59,7 @@ void HoymilesRadio::handleReceivedPackage()
|
||||
|
||||
if (nullptr != inv) {
|
||||
CommandAbstract* cmd = _commandQueue.front().get();
|
||||
uint8_t verifyResult = inv->verifyAllFragments(cmd);
|
||||
uint8_t verifyResult = inv->verifyAllFragments(*cmd);
|
||||
if (verifyResult == FRAGMENT_ALL_MISSING_RESEND) {
|
||||
Hoymiles.getMessageOutput()->println("Nothing received, resend whole request");
|
||||
sendLastPacketAgain();
|
||||
@ -105,7 +105,7 @@ void HoymilesRadio::handleReceivedPackage()
|
||||
auto inv = Hoymiles.getInverterBySerial(cmd->getTargetAddress());
|
||||
if (nullptr != inv) {
|
||||
inv->clearRxFragmentBuffer();
|
||||
sendEsbPacket(cmd);
|
||||
sendEsbPacket(*cmd);
|
||||
} else {
|
||||
Hoymiles.getMessageOutput()->println("TX: Invalid inverter found");
|
||||
_commandQueue.pop();
|
||||
@ -114,7 +114,7 @@ void HoymilesRadio::handleReceivedPackage()
|
||||
}
|
||||
}
|
||||
|
||||
void HoymilesRadio::dumpBuf(const uint8_t buf[], uint8_t len, bool appendNewline)
|
||||
void HoymilesRadio::dumpBuf(const uint8_t buf[], const uint8_t len, const bool appendNewline)
|
||||
{
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
Hoymiles.getVerboseMessageOutput()->printf("%02X ", buf[i]);
|
||||
@ -124,17 +124,17 @@ void HoymilesRadio::dumpBuf(const uint8_t buf[], uint8_t len, bool appendNewline
|
||||
}
|
||||
}
|
||||
|
||||
bool HoymilesRadio::isInitialized()
|
||||
bool HoymilesRadio::isInitialized() const
|
||||
{
|
||||
return _isInitialized;
|
||||
}
|
||||
|
||||
bool HoymilesRadio::isIdle()
|
||||
bool HoymilesRadio::isIdle() const
|
||||
{
|
||||
return !_busyFlag;
|
||||
}
|
||||
|
||||
bool HoymilesRadio::isQueueEmpty()
|
||||
bool HoymilesRadio::isQueueEmpty() const
|
||||
{
|
||||
return _commandQueue.size() == 0;
|
||||
}
|
||||
|
||||
@ -9,12 +9,12 @@
|
||||
|
||||
class HoymilesRadio {
|
||||
public:
|
||||
serial_u DtuSerial();
|
||||
virtual void setDtuSerial(uint64_t serial);
|
||||
serial_u DtuSerial() const;
|
||||
virtual void setDtuSerial(const uint64_t serial);
|
||||
|
||||
bool isIdle();
|
||||
bool isQueueEmpty();
|
||||
bool isInitialized();
|
||||
bool isIdle() const;
|
||||
bool isQueueEmpty() const;
|
||||
bool isInitialized() const;
|
||||
|
||||
void enqueCommand(std::shared_ptr<CommandAbstract> cmd)
|
||||
{
|
||||
@ -28,12 +28,12 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
static serial_u convertSerialToRadioId(serial_u serial);
|
||||
void dumpBuf(const uint8_t buf[], uint8_t len, bool appendNewline = true);
|
||||
static serial_u convertSerialToRadioId(const serial_u serial);
|
||||
static void dumpBuf(const uint8_t buf[], const uint8_t len, const bool appendNewline = true);
|
||||
|
||||
bool checkFragmentCrc(fragment_t* fragment);
|
||||
virtual void sendEsbPacket(CommandAbstract* cmd) = 0;
|
||||
void sendRetransmitPacket(uint8_t fragment_id);
|
||||
bool checkFragmentCrc(const fragment_t& fragment) const;
|
||||
virtual void sendEsbPacket(CommandAbstract& cmd) = 0;
|
||||
void sendRetransmitPacket(const uint8_t fragment_id);
|
||||
void sendLastPacketAgain();
|
||||
void handleReceivedPackage();
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ bool HoymilesRadio_CMT::cmtSwitchDtuFreq(const uint32_t to_freq_kHz)
|
||||
return true;
|
||||
}
|
||||
|
||||
void HoymilesRadio_CMT::init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio2, int8_t pin_gpio3)
|
||||
void HoymilesRadio_CMT::init(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const int8_t pin_gpio2, const int8_t pin_gpio3)
|
||||
{
|
||||
_dtuSerial.u64 = 0;
|
||||
|
||||
@ -122,15 +122,15 @@ void HoymilesRadio_CMT::loop()
|
||||
// Perform package parsing only if no packages are received
|
||||
if (!_rxBuffer.empty()) {
|
||||
fragment_t f = _rxBuffer.back();
|
||||
if (checkFragmentCrc(&f)) {
|
||||
if (checkFragmentCrc(f)) {
|
||||
|
||||
serial_u dtuId = convertSerialToRadioId(_dtuSerial);
|
||||
const serial_u dtuId = convertSerialToRadioId(_dtuSerial);
|
||||
|
||||
// The CMT RF module does not filter foreign packages by itself.
|
||||
// Has to be done manually here.
|
||||
if (memcmp(&f.fragment[5], &dtuId.b[1], 4) == 0) {
|
||||
|
||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(&f);
|
||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(f);
|
||||
|
||||
if (nullptr != inv) {
|
||||
// Save packet in inverter rx buffer
|
||||
@ -156,7 +156,7 @@ void HoymilesRadio_CMT::loop()
|
||||
handleReceivedPackage();
|
||||
}
|
||||
|
||||
void HoymilesRadio_CMT::setPALevel(int8_t paLevel)
|
||||
void HoymilesRadio_CMT::setPALevel(const int8_t paLevel)
|
||||
{
|
||||
if (!_isInitialized) {
|
||||
return;
|
||||
@ -169,7 +169,7 @@ void HoymilesRadio_CMT::setPALevel(int8_t paLevel)
|
||||
}
|
||||
}
|
||||
|
||||
void HoymilesRadio_CMT::setInverterTargetFrequency(uint32_t frequency)
|
||||
void HoymilesRadio_CMT::setInverterTargetFrequency(const uint32_t frequency)
|
||||
{
|
||||
_inverterTargetFrequency = frequency;
|
||||
if (!_isInitialized) {
|
||||
@ -178,12 +178,12 @@ void HoymilesRadio_CMT::setInverterTargetFrequency(uint32_t frequency)
|
||||
cmtSwitchDtuFreq(_inverterTargetFrequency);
|
||||
}
|
||||
|
||||
uint32_t HoymilesRadio_CMT::getInverterTargetFrequency()
|
||||
uint32_t HoymilesRadio_CMT::getInverterTargetFrequency() const
|
||||
{
|
||||
return _inverterTargetFrequency;
|
||||
}
|
||||
|
||||
bool HoymilesRadio_CMT::isConnected()
|
||||
bool HoymilesRadio_CMT::isConnected() const
|
||||
{
|
||||
if (!_isInitialized) {
|
||||
return false;
|
||||
@ -211,27 +211,27 @@ void ARDUINO_ISR_ATTR HoymilesRadio_CMT::handleInt2()
|
||||
_packetReceived = true;
|
||||
}
|
||||
|
||||
void HoymilesRadio_CMT::sendEsbPacket(CommandAbstract* cmd)
|
||||
void HoymilesRadio_CMT::sendEsbPacket(CommandAbstract& cmd)
|
||||
{
|
||||
cmd->incrementSendCount();
|
||||
cmd.incrementSendCount();
|
||||
|
||||
cmd->setRouterAddress(DtuSerial().u64);
|
||||
cmd.setRouterAddress(DtuSerial().u64);
|
||||
|
||||
_radio->stopListening();
|
||||
|
||||
if (cmd->getDataPayload()[0] == 0x56) { // @todo(tbnobody) Bad hack to identify ChannelChange Command
|
||||
if (cmd.getDataPayload()[0] == 0x56) { // @todo(tbnobody) Bad hack to identify ChannelChange Command
|
||||
cmtSwitchDtuFreq(HOY_BOOT_FREQ / 1000);
|
||||
}
|
||||
|
||||
Hoymiles.getVerboseMessageOutput()->printf("TX %s %.2f MHz --> ",
|
||||
cmd->getCommandName().c_str(), getFrequencyFromChannel(_radio->getChannel()));
|
||||
cmd->dumpDataPayload(Hoymiles.getVerboseMessageOutput());
|
||||
cmd.getCommandName().c_str(), getFrequencyFromChannel(_radio->getChannel()));
|
||||
cmd.dumpDataPayload(Hoymiles.getVerboseMessageOutput());
|
||||
|
||||
if (!_radio->write(cmd->getDataPayload(), cmd->getDataSize())) {
|
||||
if (!_radio->write(cmd.getDataPayload(), cmd.getDataSize())) {
|
||||
Hoymiles.getMessageOutput()->println("TX SPI Timeout");
|
||||
}
|
||||
cmtSwitchDtuFreq(_inverterTargetFrequency);
|
||||
_radio->startListening();
|
||||
_busyFlag = true;
|
||||
_rxTimeout.set(cmd->getTimeout());
|
||||
_rxTimeout.set(cmd.getTimeout());
|
||||
}
|
||||
|
||||
@ -18,13 +18,13 @@
|
||||
|
||||
class HoymilesRadio_CMT : public HoymilesRadio {
|
||||
public:
|
||||
void init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio2, int8_t pin_gpio3);
|
||||
void init(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const int8_t pin_gpio2, const int8_t pin_gpio3);
|
||||
void loop();
|
||||
void setPALevel(int8_t paLevel);
|
||||
void setInverterTargetFrequency(uint32_t frequency);
|
||||
uint32_t getInverterTargetFrequency();
|
||||
void setPALevel(const int8_t paLevel);
|
||||
void setInverterTargetFrequency(const uint32_t frequency);
|
||||
uint32_t getInverterTargetFrequency() const;
|
||||
|
||||
bool isConnected();
|
||||
bool isConnected() const;
|
||||
|
||||
static uint32_t getMinFrequency();
|
||||
static uint32_t getMaxFrequency();
|
||||
@ -36,7 +36,7 @@ private:
|
||||
void ARDUINO_ISR_ATTR handleInt1();
|
||||
void ARDUINO_ISR_ATTR handleInt2();
|
||||
|
||||
void sendEsbPacket(CommandAbstract* cmd);
|
||||
void sendEsbPacket(CommandAbstract& cmd);
|
||||
|
||||
std::unique_ptr<CMT2300A> _radio;
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include <Every.h>
|
||||
#include <FunctionalInterrupt.h>
|
||||
|
||||
void HoymilesRadio_NRF::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ)
|
||||
void HoymilesRadio_NRF::init(SPIClass* initialisedSpiBus, const uint8_t pinCE, const uint8_t pinIRQ)
|
||||
{
|
||||
_dtuSerial.u64 = 0;
|
||||
|
||||
@ -71,8 +71,8 @@ void HoymilesRadio_NRF::loop()
|
||||
// Perform package parsing only if no packages are received
|
||||
if (!_rxBuffer.empty()) {
|
||||
fragment_t f = _rxBuffer.back();
|
||||
if (checkFragmentCrc(&f)) {
|
||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(&f);
|
||||
if (checkFragmentCrc(f)) {
|
||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(f);
|
||||
|
||||
if (nullptr != inv) {
|
||||
// Save packet in inverter rx buffer
|
||||
@ -97,7 +97,7 @@ void HoymilesRadio_NRF::loop()
|
||||
handleReceivedPackage();
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::setPALevel(rf24_pa_dbm_e paLevel)
|
||||
void HoymilesRadio_NRF::setPALevel(const rf24_pa_dbm_e paLevel)
|
||||
{
|
||||
if (!_isInitialized) {
|
||||
return;
|
||||
@ -105,7 +105,7 @@ void HoymilesRadio_NRF::setPALevel(rf24_pa_dbm_e paLevel)
|
||||
_radio->setPALevel(paLevel);
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::setDtuSerial(uint64_t serial)
|
||||
void HoymilesRadio_NRF::setDtuSerial(const uint64_t serial)
|
||||
{
|
||||
HoymilesRadio::setDtuSerial(serial);
|
||||
|
||||
@ -115,7 +115,7 @@ void HoymilesRadio_NRF::setDtuSerial(uint64_t serial)
|
||||
openReadingPipe();
|
||||
}
|
||||
|
||||
bool HoymilesRadio_NRF::isConnected()
|
||||
bool HoymilesRadio_NRF::isConnected() const
|
||||
{
|
||||
if (!_isInitialized) {
|
||||
return false;
|
||||
@ -123,7 +123,7 @@ bool HoymilesRadio_NRF::isConnected()
|
||||
return _radio->isChipConnected();
|
||||
}
|
||||
|
||||
bool HoymilesRadio_NRF::isPVariant()
|
||||
bool HoymilesRadio_NRF::isPVariant() const
|
||||
{
|
||||
if (!_isInitialized) {
|
||||
return false;
|
||||
@ -133,15 +133,13 @@ bool HoymilesRadio_NRF::isPVariant()
|
||||
|
||||
void HoymilesRadio_NRF::openReadingPipe()
|
||||
{
|
||||
serial_u s;
|
||||
s = convertSerialToRadioId(_dtuSerial);
|
||||
const serial_u s = convertSerialToRadioId(_dtuSerial);
|
||||
_radio->openReadingPipe(1, s.u64);
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::openWritingPipe(serial_u serial)
|
||||
void HoymilesRadio_NRF::openWritingPipe(const serial_u serial)
|
||||
{
|
||||
serial_u s;
|
||||
s = convertSerialToRadioId(serial);
|
||||
const serial_u s = convertSerialToRadioId(serial);
|
||||
_radio->openWritingPipe(s.u64);
|
||||
}
|
||||
|
||||
@ -171,29 +169,29 @@ void HoymilesRadio_NRF::switchRxCh()
|
||||
_radio->startListening();
|
||||
}
|
||||
|
||||
void HoymilesRadio_NRF::sendEsbPacket(CommandAbstract* cmd)
|
||||
void HoymilesRadio_NRF::sendEsbPacket(CommandAbstract& cmd)
|
||||
{
|
||||
cmd->incrementSendCount();
|
||||
cmd.incrementSendCount();
|
||||
|
||||
cmd->setRouterAddress(DtuSerial().u64);
|
||||
cmd.setRouterAddress(DtuSerial().u64);
|
||||
|
||||
_radio->stopListening();
|
||||
_radio->setChannel(getTxNxtChannel());
|
||||
|
||||
serial_u s;
|
||||
s.u64 = cmd->getTargetAddress();
|
||||
s.u64 = cmd.getTargetAddress();
|
||||
openWritingPipe(s);
|
||||
_radio->setRetries(3, 15);
|
||||
|
||||
Hoymiles.getVerboseMessageOutput()->printf("TX %s Channel: %d --> ",
|
||||
cmd->getCommandName().c_str(), _radio->getChannel());
|
||||
cmd->dumpDataPayload(Hoymiles.getVerboseMessageOutput());
|
||||
_radio->write(cmd->getDataPayload(), cmd->getDataSize());
|
||||
cmd.getCommandName().c_str(), _radio->getChannel());
|
||||
cmd.dumpDataPayload(Hoymiles.getVerboseMessageOutput());
|
||||
_radio->write(cmd.getDataPayload(), cmd.getDataSize());
|
||||
|
||||
_radio->setRetries(0, 0);
|
||||
openReadingPipe();
|
||||
_radio->setChannel(getRxNxtChannel());
|
||||
_radio->startListening();
|
||||
_busyFlag = true;
|
||||
_rxTimeout.set(cmd->getTimeout());
|
||||
_rxTimeout.set(cmd.getTimeout());
|
||||
}
|
||||
|
||||
@ -13,14 +13,14 @@
|
||||
|
||||
class HoymilesRadio_NRF : public HoymilesRadio {
|
||||
public:
|
||||
void init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ);
|
||||
void init(SPIClass* initialisedSpiBus, const uint8_t pinCE, const uint8_t pinIRQ);
|
||||
void loop();
|
||||
void setPALevel(rf24_pa_dbm_e paLevel);
|
||||
void setPALevel(const rf24_pa_dbm_e paLevel);
|
||||
|
||||
virtual void setDtuSerial(uint64_t serial);
|
||||
virtual void setDtuSerial(const uint64_t serial);
|
||||
|
||||
bool isConnected();
|
||||
bool isPVariant();
|
||||
bool isConnected() const;
|
||||
bool isPVariant() const;
|
||||
|
||||
private:
|
||||
void ARDUINO_ISR_ATTR handleIntr();
|
||||
@ -28,9 +28,9 @@ private:
|
||||
uint8_t getTxNxtChannel();
|
||||
void switchRxCh();
|
||||
void openReadingPipe();
|
||||
void openWritingPipe(serial_u serial);
|
||||
void openWritingPipe(const serial_u serial);
|
||||
|
||||
void sendEsbPacket(CommandAbstract* cmd);
|
||||
void sendEsbPacket(CommandAbstract& cmd);
|
||||
|
||||
std::unique_ptr<SPIClass> _spiPtr;
|
||||
std::unique_ptr<RF24> _radio;
|
||||
|
||||
@ -1,13 +1,31 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
*/
|
||||
|
||||
/*
|
||||
This command is used to send a limit to the inverter.
|
||||
|
||||
Derives from DevControlCommand.
|
||||
|
||||
Command structure:
|
||||
SCmd: Sub-Command ID. Is always 0x0b
|
||||
Limit: limit to be set in the inverter
|
||||
Type: absolute / relative and persistant/non-persistant
|
||||
|
||||
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||
-------------------------------------------------------------------------------------------------------------------
|
||||
|<------ CRC16 ------>|
|
||||
51 71 60 35 46 80 12 23 04 81 0b 00 00 00 00 00 00 00 00 -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^ ^^^^^ ^^^^^ ^^
|
||||
ID Target Addr Source Addr Cmd SCmd ? Limit Type CRC16 CRC8
|
||||
*/
|
||||
#include "ActivePowerControlCommand.h"
|
||||
#include "inverters/InverterAbstract.h"
|
||||
|
||||
#define CRC_SIZE 6
|
||||
|
||||
ActivePowerControlCommand::ActivePowerControlCommand(uint64_t target_address, uint64_t router_address)
|
||||
ActivePowerControlCommand::ActivePowerControlCommand(const uint64_t target_address, const uint64_t router_address)
|
||||
: DevControlCommand(target_address, router_address)
|
||||
{
|
||||
_payload[10] = 0x0b;
|
||||
@ -17,21 +35,21 @@ ActivePowerControlCommand::ActivePowerControlCommand(uint64_t target_address, ui
|
||||
_payload[14] = 0x00;
|
||||
_payload[15] = 0x00;
|
||||
|
||||
udpateCRC(CRC_SIZE); // 2 byte crc
|
||||
udpateCRC(CRC_SIZE); // 6 byte crc
|
||||
|
||||
_payload_size = 18;
|
||||
|
||||
setTimeout(2000);
|
||||
}
|
||||
|
||||
String ActivePowerControlCommand::getCommandName()
|
||||
String ActivePowerControlCommand::getCommandName() const
|
||||
{
|
||||
return "ActivePowerControl";
|
||||
}
|
||||
|
||||
void ActivePowerControlCommand::setActivePowerLimit(float limit, PowerLimitControlType type)
|
||||
void ActivePowerControlCommand::setActivePowerLimit(const float limit, const PowerLimitControlType type)
|
||||
{
|
||||
uint16_t l = limit * 10;
|
||||
const uint16_t l = limit * 10;
|
||||
|
||||
// limit
|
||||
_payload[12] = (l >> 8) & 0xff;
|
||||
@ -44,30 +62,30 @@ void ActivePowerControlCommand::setActivePowerLimit(float limit, PowerLimitContr
|
||||
udpateCRC(CRC_SIZE);
|
||||
}
|
||||
|
||||
bool ActivePowerControlCommand::handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id)
|
||||
bool ActivePowerControlCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id)
|
||||
{
|
||||
if (!DevControlCommand::handleResponse(inverter, fragment, max_fragment_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((getType() == PowerLimitControlType::RelativNonPersistent) || (getType() == PowerLimitControlType::RelativPersistent)) {
|
||||
inverter->SystemConfigPara()->setLimitPercent(getLimit());
|
||||
inverter.SystemConfigPara()->setLimitPercent(getLimit());
|
||||
} else {
|
||||
uint16_t max_power = inverter->DevInfo()->getMaxPower();
|
||||
const uint16_t max_power = inverter.DevInfo()->getMaxPower();
|
||||
if (max_power > 0) {
|
||||
inverter->SystemConfigPara()->setLimitPercent(static_cast<float>(getLimit()) / max_power * 100);
|
||||
inverter.SystemConfigPara()->setLimitPercent(static_cast<float>(getLimit()) / max_power * 100);
|
||||
} else {
|
||||
// TODO(tbnobody): Not implemented yet because we only can publish the percentage value
|
||||
}
|
||||
}
|
||||
inverter->SystemConfigPara()->setLastUpdateCommand(millis());
|
||||
inverter->SystemConfigPara()->setLastLimitCommandSuccess(CMD_OK);
|
||||
inverter.SystemConfigPara()->setLastUpdateCommand(millis());
|
||||
inverter.SystemConfigPara()->setLastLimitCommandSuccess(CMD_OK);
|
||||
return true;
|
||||
}
|
||||
|
||||
float ActivePowerControlCommand::getLimit()
|
||||
float ActivePowerControlCommand::getLimit() const
|
||||
{
|
||||
uint16_t l = (((uint16_t)_payload[12] << 8) | _payload[13]);
|
||||
const uint16_t l = (((uint16_t)_payload[12] << 8) | _payload[13]);
|
||||
return l / 10;
|
||||
}
|
||||
|
||||
@ -76,7 +94,7 @@ PowerLimitControlType ActivePowerControlCommand::getType()
|
||||
return (PowerLimitControlType)(((uint16_t)_payload[14] << 8) | _payload[15]);
|
||||
}
|
||||
|
||||
void ActivePowerControlCommand::gotTimeout(InverterAbstract* inverter)
|
||||
void ActivePowerControlCommand::gotTimeout(InverterAbstract& inverter)
|
||||
{
|
||||
inverter->SystemConfigPara()->setLastLimitCommandSuccess(CMD_NOK);
|
||||
inverter.SystemConfigPara()->setLastLimitCommandSuccess(CMD_NOK);
|
||||
}
|
||||
@ -12,14 +12,14 @@ typedef enum { // ToDo: to be verified by field tests
|
||||
|
||||
class ActivePowerControlCommand : public DevControlCommand {
|
||||
public:
|
||||
explicit ActivePowerControlCommand(uint64_t target_address = 0, uint64_t router_address = 0);
|
||||
explicit ActivePowerControlCommand(const uint64_t target_address = 0, const uint64_t router_address = 0);
|
||||
|
||||
virtual String getCommandName();
|
||||
virtual String getCommandName() const;
|
||||
|
||||
virtual bool handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id);
|
||||
virtual void gotTimeout(InverterAbstract* inverter);
|
||||
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id);
|
||||
virtual void gotTimeout(InverterAbstract& inverter);
|
||||
|
||||
void setActivePowerLimit(float limit, PowerLimitControlType type = RelativNonPersistent);
|
||||
float getLimit();
|
||||
void setActivePowerLimit(const float limit, const PowerLimitControlType type = RelativNonPersistent);
|
||||
float getLimit() const;
|
||||
PowerLimitControlType getType();
|
||||
};
|
||||
@ -1,11 +1,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
*/
|
||||
|
||||
/*
|
||||
This command is used to fetch the eventlog from the inverter.
|
||||
|
||||
Derives from MultiDataCommand
|
||||
|
||||
Command structure:
|
||||
* DT: this specific command uses 0x11
|
||||
* AlarmId: The last event id received from the inverter or zero in case that no events
|
||||
has been received yet. --> Not Implemented yet
|
||||
|
||||
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
|<------------------- CRC16 --------------------->|
|
||||
15 71 60 35 46 80 12 23 04 80 11 00 65 72 06 B8 00 00 00 00 00 00 00 00 00 00 00 -- -- -- -- --
|
||||
^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^^^^^^^ ^^^^^ ^^^^^ ^^^^^^^^^^^ ^^^^^ ^^
|
||||
ID Target Addr Source Addr Idx DT ? Time Gap AlarmId Password CRC16 CRC8
|
||||
*/
|
||||
#include "AlarmDataCommand.h"
|
||||
#include "inverters/InverterAbstract.h"
|
||||
|
||||
AlarmDataCommand::AlarmDataCommand(uint64_t target_address, uint64_t router_address, time_t time)
|
||||
AlarmDataCommand::AlarmDataCommand(const uint64_t target_address, const uint64_t router_address, const time_t time)
|
||||
: MultiDataCommand(target_address, router_address)
|
||||
{
|
||||
setTime(time);
|
||||
@ -13,12 +31,12 @@ AlarmDataCommand::AlarmDataCommand(uint64_t target_address, uint64_t router_addr
|
||||
setTimeout(750);
|
||||
}
|
||||
|
||||
String AlarmDataCommand::getCommandName()
|
||||
String AlarmDataCommand::getCommandName() const
|
||||
{
|
||||
return "AlarmData";
|
||||
}
|
||||
|
||||
bool AlarmDataCommand::handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id)
|
||||
bool AlarmDataCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id)
|
||||
{
|
||||
// Check CRC of whole payload
|
||||
if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) {
|
||||
@ -27,19 +45,19 @@ bool AlarmDataCommand::handleResponse(InverterAbstract* inverter, fragment_t fra
|
||||
|
||||
// Move all fragments into target buffer
|
||||
uint8_t offs = 0;
|
||||
inverter->EventLog()->beginAppendFragment();
|
||||
inverter->EventLog()->clearBuffer();
|
||||
inverter.EventLog()->beginAppendFragment();
|
||||
inverter.EventLog()->clearBuffer();
|
||||
for (uint8_t i = 0; i < max_fragment_id; i++) {
|
||||
inverter->EventLog()->appendFragment(offs, fragment[i].fragment, fragment[i].len);
|
||||
inverter.EventLog()->appendFragment(offs, fragment[i].fragment, fragment[i].len);
|
||||
offs += (fragment[i].len);
|
||||
}
|
||||
inverter->EventLog()->endAppendFragment();
|
||||
inverter->EventLog()->setLastAlarmRequestSuccess(CMD_OK);
|
||||
inverter->EventLog()->setLastUpdate(millis());
|
||||
inverter.EventLog()->endAppendFragment();
|
||||
inverter.EventLog()->setLastAlarmRequestSuccess(CMD_OK);
|
||||
inverter.EventLog()->setLastUpdate(millis());
|
||||
return true;
|
||||
}
|
||||
|
||||
void AlarmDataCommand::gotTimeout(InverterAbstract* inverter)
|
||||
void AlarmDataCommand::gotTimeout(InverterAbstract& inverter)
|
||||
{
|
||||
inverter->EventLog()->setLastAlarmRequestSuccess(CMD_NOK);
|
||||
inverter.EventLog()->setLastAlarmRequestSuccess(CMD_NOK);
|
||||
}
|
||||
@ -5,10 +5,10 @@
|
||||
|
||||
class AlarmDataCommand : public MultiDataCommand {
|
||||
public:
|
||||
explicit AlarmDataCommand(uint64_t target_address = 0, uint64_t router_address = 0, time_t time = 0);
|
||||
explicit AlarmDataCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, const time_t time = 0);
|
||||
|
||||
virtual String getCommandName();
|
||||
virtual String getCommandName() const;
|
||||
|
||||
virtual bool handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id);
|
||||
virtual void gotTimeout(InverterAbstract* inverter);
|
||||
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id);
|
||||
virtual void gotTimeout(InverterAbstract& inverter);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user