#include "utils.h" #include #include #include #include "pico/sleep.h" #include "pico/stdlib.h" // #include "stdlib.h" #include "hardware/clocks.h" #include "hardware/rosc.h" #include "hardware/structs/scb.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; } chrono::year_month_day 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()); chrono::year_month_day date{chrono::year{year}, chrono::month{(uint)month}, chrono::day{(uint)day}}; return date; } std::vector split(const std::string &s, const std::string &delimiter) { std::vector 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 parseCsv(const std::string &csv) { istringstream stream(csv); string line{""}; vector 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::iterator it; it = std::find_if(wasteDates.begin(), wasteDates.end(), [&date](const WasteDate &x) { return date == x.date; }); 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) { printf("Going to sleep...\n"); 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; } else if (dt.day == daysPerMonth[dt.month]) { dt.month = (dt.month + 1) % 12; dt.day = 1; } else { dt.day += 1; } } void add_one_hour(datetime_t &dt) { if (dt.hour == 23) { add_one_day(dt); dt.hour = 0; } else { dt.hour += 1; } }