283 lines
7.4 KiB
C++
283 lines
7.4 KiB
C++
#include "utils.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
#include "hardware/clocks.h"
|
|
#include "hardware/rosc.h"
|
|
#include "hardware/structs/scb.h"
|
|
#include "pico/sleep.h"
|
|
#include "pico/stdlib.h"
|
|
|
|
using namespace std;
|
|
|
|
bool isDST(const datetime_t &dt) {
|
|
// January, february, november and december are out.
|
|
if (dt.month < 3 || dt.month > 10) {
|
|
return false;
|
|
}
|
|
|
|
// April to September are in
|
|
if (dt.month > 3 && dt.month < 10) {
|
|
return true;
|
|
}
|
|
|
|
int previousSunday = dt.day - dt.dotw;
|
|
|
|
// In march, we are DST if our previous sunday was on or after the 25th.
|
|
if (dt.month == 3) {
|
|
return previousSunday >= 25;
|
|
}
|
|
|
|
// In October we must be before the last sunday to be DST.
|
|
// That means the previous sunday must be before the 25st.
|
|
return previousSunday < 25;
|
|
}
|
|
|
|
int8_t calcDotw(int year, int month, int day) {
|
|
int mon;
|
|
if (month > 2)
|
|
mon = month; // for march to december month code is same as month
|
|
else {
|
|
mon = (12 + month); // for Jan and Feb, month code will be 13 and 14
|
|
year--; // decrease year for month Jan and Feb
|
|
}
|
|
int y = year % 100; // last two digit
|
|
int c = year / 100; // first two digit
|
|
int w = (day + floor((13 * (mon + 1)) / 5) + y + floor(y / 4) + floor(c / 4) - (2 * c));
|
|
w = (w % 7) - 1;
|
|
return w;
|
|
}
|
|
|
|
datetime_t stringToDate(const std::string &dateStr) {
|
|
istringstream partss(dateStr);
|
|
string day_str, month_str, year_str;
|
|
|
|
getline(partss, day_str, '.');
|
|
getline(partss, month_str, '.');
|
|
getline(partss, year_str, '.');
|
|
|
|
int day = atoi(day_str.c_str());
|
|
int month = atoi(month_str.c_str());
|
|
int year = atoi(year_str.c_str());
|
|
|
|
datetime_t date;
|
|
date.year = year;
|
|
date.month = month;
|
|
date.day = day;
|
|
date.dotw = calcDotw(year, month, day);
|
|
date.hour = 0;
|
|
date.min = 0;
|
|
date.sec = 0;
|
|
|
|
return date;
|
|
}
|
|
|
|
std::vector<std::string> split(const std::string &s, const std::string &delimiter) {
|
|
std::vector<std::string> result;
|
|
std::string::size_type start{0};
|
|
std::string::size_type pos{0};
|
|
do {
|
|
pos = s.find_first_of(delimiter, start);
|
|
result.push_back(s.substr(start, pos - start));
|
|
start = pos + 1;
|
|
} while (pos != std::string::npos);
|
|
return result;
|
|
}
|
|
|
|
std::vector<WasteDate> parseCsv(const std::string &csv) {
|
|
istringstream stream(csv);
|
|
string line{""};
|
|
vector<WasteDate> wasteDates;
|
|
|
|
// Get rid of the first line (header)
|
|
getline(stream, line);
|
|
|
|
while (getline(stream, line)) {
|
|
auto tokenVec = split(line, ";");
|
|
|
|
for (unsigned i = 0; i < tokenVec.size(); i++) {
|
|
string token = tokenVec.at(i);
|
|
|
|
if (token.length() == 0)
|
|
continue;
|
|
|
|
auto date = stringToDate(token);
|
|
|
|
// Take existing date or create a new one.
|
|
std::vector<WasteDate>::iterator it;
|
|
it = std::find_if(wasteDates.begin(), wasteDates.end(), [&date](const WasteDate &x) {
|
|
return date.year == x.date.year && date.month == x.date.month &&
|
|
date.day == x.date.day;
|
|
});
|
|
if (it == wasteDates.end()) {
|
|
WasteDate wd;
|
|
wd.date = date;
|
|
wasteDates.push_back(wd);
|
|
it = std::prev(wasteDates.end());
|
|
}
|
|
|
|
switch (i) {
|
|
case 0:
|
|
it->wasteTypes.push_back(Waste::GelberSack);
|
|
break;
|
|
case 1:
|
|
it->wasteTypes.push_back(Waste::Papiertonne);
|
|
break;
|
|
case 2:
|
|
it->wasteTypes.push_back(Waste::Biotonne);
|
|
break;
|
|
case 3:
|
|
it->wasteTypes.push_back(Waste::Restmuell);
|
|
break;
|
|
case 4:
|
|
it->wasteTypes.push_back(Waste::Problemstoffmobil);
|
|
break;
|
|
default:
|
|
#ifdef DEBUG
|
|
printf("Unknown waste token detected.\n");
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return wasteDates;
|
|
}
|
|
|
|
int wifi_setup(uint32_t country, const string &ssid, const string &pw, bool firstTry) {
|
|
if (firstTry) {
|
|
if (cyw43_arch_init_with_country(country)) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
cyw43_arch_enable_sta_mode();
|
|
|
|
netif_set_hostname(netif_default, "AbfallPicoW");
|
|
|
|
if (cyw43_arch_wifi_connect_async(ssid.c_str(), pw.c_str(), CYW43_AUTH_WPA2_MIXED_PSK)) {
|
|
return 2;
|
|
}
|
|
|
|
int flashrate = 1'000;
|
|
int status = CYW43_LINK_UP + 1;
|
|
|
|
while (status >= 0 && status != CYW43_LINK_UP) {
|
|
int status_new = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
|
|
|
|
if (status_new != status) {
|
|
status = status_new;
|
|
if (status < 0) {
|
|
continue;
|
|
}
|
|
flashrate = flashrate / (status + 1);
|
|
}
|
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
|
|
sleep_ms(flashrate);
|
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
|
|
sleep_ms(flashrate);
|
|
}
|
|
|
|
if (status < 0) {
|
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
|
|
} else {
|
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
|
|
#ifdef DEBUG
|
|
printf("IP: %s\n", ip4addr_ntoa(netif_ip_addr4(netif_default)));
|
|
#endif
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void wifi_enable() {
|
|
const uint32_t country{CYW43_COUNTRY_GERMANY};
|
|
|
|
bool firstTry = true;
|
|
int res = -1;
|
|
do {
|
|
if (firstTry) {
|
|
res = wifi_setup(country, WLAN_SSID, WLAN_PW,
|
|
true); // WLAN_SSID and WLAN_PW come from CMakeLists.txt
|
|
firstTry = false;
|
|
} else {
|
|
#ifdef DEBUG
|
|
printf("Setting up connection failed. Trying again after 5 sec...\n");
|
|
#endif
|
|
sleep_ms(5000);
|
|
res = wifi_setup(country, WLAN_SSID, WLAN_PW,
|
|
false); // WLAN_SSID and WLAN_PW come from CMakeLists.txt
|
|
}
|
|
|
|
} while (res != CYW43_LINK_UP);
|
|
}
|
|
|
|
void wifi_disable() {
|
|
|
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
|
|
cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA);
|
|
cyw43_arch_deinit();
|
|
}
|
|
|
|
void recover_from_sleep(uint scb_orig, uint clock0_orig, uint clock1_orig) {
|
|
|
|
// Re-enable ring Oscillator control
|
|
rosc_write(&rosc_hw->ctrl, ROSC_CTRL_ENABLE_BITS);
|
|
|
|
// reset procs back to default
|
|
scb_hw->scr = scb_orig;
|
|
clocks_hw->sleep_en0 = clock0_orig;
|
|
clocks_hw->sleep_en1 = clock1_orig;
|
|
|
|
// reset clocks
|
|
clocks_init();
|
|
stdio_init_all();
|
|
|
|
return;
|
|
}
|
|
|
|
void perform_sleep(datetime_t &untilDt) {
|
|
#ifdef DEBUG
|
|
printf("Going to sleep...\n");
|
|
#endif
|
|
uart_default_tx_wait_blocking();
|
|
|
|
sleep_goto_sleep_until(&untilDt, nullptr);
|
|
}
|
|
|
|
void add_one_day(datetime_t &dt) {
|
|
int daysPerMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
// Is it a leap year?
|
|
if ((dt.year % 4 == 0 && dt.year % 100 != 0) || dt.year % 400 == 0) {
|
|
daysPerMonth[2] = 29;
|
|
}
|
|
|
|
if (dt.month == 12 && dt.day == daysPerMonth[12]) {
|
|
dt.year += 1;
|
|
dt.month = 1;
|
|
dt.day = 1;
|
|
dt.dotw = (dt.dotw + 1) % 7;
|
|
} else if (dt.day == daysPerMonth[dt.month]) {
|
|
dt.month = (dt.month + 1) % 12;
|
|
dt.day = 1;
|
|
dt.dotw = (dt.dotw + 1) % 7;
|
|
} else {
|
|
dt.day += 1;
|
|
dt.dotw = (dt.dotw + 1) % 7;
|
|
}
|
|
}
|
|
|
|
void add_one_hour(datetime_t &dt) {
|
|
if (dt.hour == 23) {
|
|
add_one_day(dt);
|
|
dt.hour = 0;
|
|
} else {
|
|
dt.hour += 1;
|
|
}
|
|
}
|