ESP32-PaxCounter/src/main.cpp

474 lines
15 KiB
C++
Raw Normal View History

2018-06-10 22:46:13 +02:00
/*
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
2018-06-10 22:46:13 +02:00
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
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.
2019-04-07 21:54:19 +02:00
NOTE:
2018-06-10 22:46:13 +02:00
Parts of the source files in this repository are made available under different
licenses. Refer to LICENSE.txt file in repository for more details.
2018-09-22 21:26:11 +02:00
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
2019-03-03 12:57:00 +01:00
// Tasks and timers:
2018-09-22 21:26:11 +02:00
Task Core Prio Purpose
2019-03-03 12:57:00 +01:00
-------------------------------------------------------------------------------
ledloop 0 3 blinks LEDs
2018-10-03 16:24:45 +02:00
spiloop 0 2 reads/writes data on spi interface
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
2019-04-07 21:54:19 +02:00
clockloop 1 4 generates realtime telegrams for external clock
timesync_req 1 3 processes realtime time sync requests
2019-04-15 12:57:55 +02:00
irqhandler 1 2 display, timesync, gps, etc. triggered by timers
2018-11-25 16:05:30 +01:00
gpsloop 1 2 reads data from GPS via serial or i2c
bmeloop 1 1 reads data from BME sensor via i2c
2019-04-07 12:27:38 +02:00
looptask 1 1 runs the LMIC LoRa stack (arduino loop)
IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator
2018-09-22 21:26:11 +02:00
2018-12-22 21:40:43 +01:00
Low priority numbers denote low priority tasks.
Tasks using i2c bus all must have same priority, because using mutex semaphore
(irqhandler, bmeloop)
2019-04-07 21:54:19 +02:00
NOTE: Changing any timings will have impact on time accuracy of whole code.
So don't do it if you do not own a digital oscilloscope.
2019-03-03 12:57:00 +01:00
// ESP32 hardware timers
-------------------------------------------------------------------------------
2019-03-19 00:02:35 +01:00
0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS)
1 ppsIRQ -> pps clock irq -> 1sec
2019-04-15 13:46:58 +02:00
2 gpsIRQ -> gps store data -> 300ms
2019-05-07 21:17:06 +02:00
3 MatrixDisplayIRQ -> matrix mux cycle -> 0,5ms (MATRIX_DISPLAY_SCAN_US)
2019-03-03 12:57:00 +01:00
// Interrupt routines
-------------------------------------------------------------------------------
fired by hardware
2019-03-24 19:50:49 +01:00
DisplayIRQ -> esp32 timer 0 -> irqHandlerTask (Core 1)
CLOCKIRQ -> esp32 timer 1 -> ClockTask (Core 1)
GpsIRQ -> esp32 timer 2 -> irqHandlerTask (Core 1)
2019-03-24 19:50:49 +01:00
ButtonIRQ -> external gpio -> irqHandlerTask (Core 1)
2019-03-03 12:57:00 +01:00
fired by software (Ticker.h)
2019-03-24 19:50:49 +01:00
TIMESYNC_IRQ -> timeSync() -> irqHandlerTask (Core 1)
CYLCIC_IRQ -> housekeeping() -> irqHandlerTask (Core 1)
SENDCYCLE_IRQ -> sendcycle() -> irqHandlerTask (Core 1)
2019-03-03 12:57:00 +01:00
// External RTC timer (if present)
-------------------------------------------------------------------------------
triggers pps 1 sec impulse
2018-09-22 21:26:11 +02:00
2018-06-10 22:46:13 +02:00
*/
// Basic Config
2018-07-17 11:53:43 +02:00
#include "main.h"
2018-06-10 22:46:13 +02:00
2018-09-15 18:59:20 +02:00
configData_t cfg; // struct holds current device configuration
2018-07-14 20:07:33 +02:00
char display_line6[16], display_line7[16]; // display buffers
2018-09-23 22:12:10 +02:00
uint8_t volatile channel = 0; // channel rotation counter
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
2018-12-22 14:37:47 +01:00
batt_voltage = 0; // globals for display
hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL, *matrixDisplayIRQ = NULL,
*gpsIRQ = NULL;
2019-04-08 21:22:54 +02:00
TaskHandle_t irqHandlerTask = NULL, ClockTask = NULL;
2019-03-19 01:46:20 +01:00
SemaphoreHandle_t I2Caccess;
bool volatile TimePulseTick = false;
time_t volatile gps_pps_time = 0;
2019-02-24 01:44:55 +01:00
time_t userUTCTime = 0;
2019-02-27 00:52:27 +01:00
timesource_t timeSource = _unsynced;
2019-02-21 23:17:01 +01:00
2018-12-22 14:37:47 +01:00
// container holding unique MAC address hashes with Memory Alloctor using PSRAM,
// if present
std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
2018-06-10 22:46:13 +02:00
// initialize payload encoder
2018-07-19 22:33:37 +02:00
PayloadConvert payload(PAYLOAD_BUFFER_SIZE);
2018-06-16 19:50:36 +02:00
2019-02-22 22:28:35 +01:00
// set Time Zone for user setting from paxcounter.conf
TimeChangeRule myDST = DAYLIGHT_TIME;
TimeChangeRule mySTD = STANDARD_TIME;
Timezone myTZ(myDST, mySTD);
2018-06-10 22:46:13 +02:00
// local Tag for logging
2019-02-27 00:52:27 +01:00
static const char TAG[] = __FILE__;
2018-06-10 22:46:13 +02:00
void setup() {
2018-06-17 11:40:52 +02:00
2018-08-02 11:33:02 +02:00
char features[100] = "";
2018-06-10 22:46:13 +02:00
2019-02-24 01:44:55 +01:00
// create some semaphores for syncing / mutexing tasks
2019-02-02 10:35:20 +01:00
I2Caccess = xSemaphoreCreateMutex(); // for access management of i2c bus
2019-02-04 20:02:30 +01:00
if (I2Caccess)
2019-02-12 23:57:36 +01:00
xSemaphoreGive(I2Caccess); // Flag the i2c bus available for use
2019-03-24 01:05:13 +01:00
// disable brownout detection
2018-06-10 22:46:13 +02:00
#ifdef DISABLE_BROWNOUT
// register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
2018-09-23 22:12:10 +02:00
(*((uint32_t volatile *)ETS_UNCACHED_ADDR((DR_REG_RTCCNTL_BASE + 0xd4)))) = 0;
2018-06-10 22:46:13 +02:00
#endif
// setup debug output or silence device
2019-03-13 21:15:28 +01:00
#if (VERBOSE)
2018-06-10 22:46:13 +02:00
Serial.begin(115200);
esp_log_level_set("*", ESP_LOG_VERBOSE);
#else
// mute logs completely by redirecting them to silence function
esp_log_level_set("*", ESP_LOG_NONE);
#endif
2018-11-25 16:05:30 +01:00
ESP_LOGI(TAG, "Starting %s v%s", PRODUCTNAME, PROGVERSION);
// print chip information on startup if in verbose mode
2019-03-13 21:15:28 +01:00
#if (VERBOSE)
2018-11-25 16:05:30 +01:00
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
ESP_LOGI(TAG,
"This is ESP32 chip with %d CPU cores, WiFi%s%s, silicon revision "
"%d, %dMB %s Flash",
chip_info.cores, (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
chip_info.revision, spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded"
: "external");
2018-12-21 00:35:21 +01:00
ESP_LOGI(TAG, "Internal Total heap %d, internal Free Heap %d",
ESP.getHeapSize(), ESP.getFreeHeap());
2018-12-22 14:37:47 +01:00
#ifdef BOARD_HAS_PSRAM
2018-12-21 00:35:21 +01:00
ESP_LOGI(TAG, "SPIRam Total heap %d, SPIRam Free Heap %d", ESP.getPsramSize(),
ESP.getFreePsram());
2018-12-22 14:37:47 +01:00
#endif
2018-12-21 00:35:21 +01:00
ESP_LOGI(TAG, "ChipRevision %d, Cpu Freq %d, SDK Version %s",
ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
ESP_LOGI(TAG, "Flash Size %d, Flash Speed %d", ESP.getFlashChipSize(),
ESP.getFlashChipSpeed());
ESP_LOGI(TAG, "Wifi/BT software coexist version %s", esp_coex_version_get());
2019-03-19 00:02:35 +01:00
#if (HAS_LORA)
ESP_LOGI(TAG, "IBM LMIC version %d.%d.%d", LMIC_VERSION_MAJOR,
LMIC_VERSION_MINOR, LMIC_VERSION_BUILD);
ESP_LOGI(TAG, "Arduino LMIC version %d.%d.%d.%d",
ARDUINO_LMIC_VERSION_GET_MAJOR(ARDUINO_LMIC_VERSION),
ARDUINO_LMIC_VERSION_GET_MINOR(ARDUINO_LMIC_VERSION),
ARDUINO_LMIC_VERSION_GET_PATCH(ARDUINO_LMIC_VERSION),
ARDUINO_LMIC_VERSION_GET_LOCAL(ARDUINO_LMIC_VERSION));
2019-03-07 21:30:09 +01:00
showLoraKeys();
#endif // HAS_LORA
2018-11-25 16:05:30 +01:00
2019-03-19 00:02:35 +01:00
#if (HAS_GPS)
ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion());
2018-11-25 16:05:30 +01:00
#endif
#endif // verbose
2018-09-22 21:26:11 +02:00
// read (and initialize on first run) runtime settings from NVRAM
loadConfig(); // includes initialize if necessary
2018-06-10 22:46:13 +02:00
2018-12-22 14:37:47 +01:00
#ifdef BOARD_HAS_PSRAM
2018-12-22 18:01:45 +01:00
assert(psramFound());
ESP_LOGI(TAG, "PSRAM found and initialized");
strcat_P(features, " PSRAM");
2018-12-22 14:37:47 +01:00
#endif
2019-03-24 00:15:04 +01:00
// set external power mode
2019-03-23 11:04:22 +01:00
#ifdef EXT_POWER_SW
pinMode(EXT_POWER_SW, OUTPUT);
digitalWrite(EXT_POWER_SW, EXT_POWER_ON);
strcat_P(features, " VEXT");
2019-03-19 00:02:35 +01:00
#endif
2019-03-23 11:04:22 +01:00
#ifdef BAT_MEASURE_EN
2019-03-24 01:05:13 +01:00
pinMode(BAT_MEASURE_EN, OUTPUT);
#endif
2018-12-22 18:01:45 +01:00
// initialize leds
2018-09-22 21:26:11 +02:00
#if (HAS_LED != NOT_A_PIN)
pinMode(HAS_LED, OUTPUT);
strcat_P(features, " LED");
2019-03-24 16:18:29 +01:00
#ifdef HAS_TWO_LED
pinMode(HAS_TWO_LED, OUTPUT);
2019-03-24 01:05:13 +01:00
strcat_P(features, " LED1");
#endif
// use LED for power display if we have additional RGB LED, else for status
2018-10-24 18:07:41 +02:00
#ifdef HAS_RGB_LED
switch_LED(LED_ON);
2018-11-25 16:05:30 +01:00
strcat_P(features, " RGB");
rgb_set_color(COLOR_PINK);
2018-10-24 18:07:41 +02:00
#endif
2018-09-22 21:26:11 +02:00
#endif
2018-10-24 18:07:41 +02:00
2018-11-25 16:05:30 +01:00
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
// start led loop
2019-01-28 00:38:31 +01:00
ESP_LOGI(TAG, "Starting LED Controller...");
2018-11-25 16:05:30 +01:00
xTaskCreatePinnedToCore(ledLoop, // task function
"ledloop", // name of task
1024, // stack size of task
(void *)1, // parameter of the task
3, // priority of the task
&ledLoopTask, // task handle
0); // CPU core
2018-09-22 21:26:11 +02:00
#endif
2018-06-10 22:46:13 +02:00
2019-01-20 22:38:53 +01:00
// initialize wifi antenna
2018-09-22 21:26:11 +02:00
#ifdef HAS_ANTENNA_SWITCH
strcat_P(features, " ANT");
antenna_init();
antenna_select(cfg.wifiant);
#endif
2018-06-10 22:46:13 +02:00
2018-09-22 21:26:11 +02:00
// initialize battery status
2019-03-23 11:04:22 +01:00
#ifdef BAT_MEASURE_ADC
2018-09-22 21:26:11 +02:00
strcat_P(features, " BATT");
calibrate_voltage();
batt_voltage = read_voltage();
#endif
2019-03-13 21:15:28 +01:00
#if (USE_OTA)
2018-09-24 16:36:11 +02:00
strcat_P(features, " OTA");
2018-09-22 21:26:11 +02:00
// reboot to firmware update mode if ota trigger switch is set
if (cfg.runmode == 1) {
cfg.runmode = 0;
saveConfig();
start_ota_update();
}
2018-09-24 16:36:11 +02:00
#endif
2018-08-11 19:12:04 +02:00
2018-12-02 18:22:57 +01:00
// start BLE scan callback if BLE function is enabled in NVRAM configuration
// or switch off bluetooth, if not compiled
2019-03-13 21:15:28 +01:00
#if (BLECOUNTER)
2018-12-02 18:22:57 +01:00
strcat_P(features, " BLE");
if (cfg.blescan) {
ESP_LOGI(TAG, "Starting Bluetooth...");
start_BLEscan();
} else
btStop();
#else
// remove bluetooth stack to gain more free memory
2018-12-02 18:22:57 +01:00
btStop();
ESP_ERROR_CHECK(esp_bt_mem_release(ESP_BT_MODE_BTDM));
2019-07-21 19:21:11 +02:00
ESP_ERROR_CHECK(esp_coex_preference_set(
ESP_COEX_PREFER_WIFI)); // configure Wifi/BT coexist lib
2018-12-02 18:22:57 +01:00
#endif
2018-09-22 21:26:11 +02:00
// initialize gps
2019-03-19 00:02:35 +01:00
#if (HAS_GPS)
2018-09-22 21:26:11 +02:00
strcat_P(features, " GPS");
2018-11-25 16:05:30 +01:00
if (gps_init()) {
2019-01-28 00:38:31 +01:00
ESP_LOGI(TAG, "Starting GPS Feed...");
2018-11-25 16:05:30 +01:00
xTaskCreatePinnedToCore(gps_loop, // task function
"gpsloop", // name of task
2048, // stack size of task
(void *)1, // parameter of the task
2, // priority of the task
&GpsTask, // task handle
1); // CPU core
}
2018-08-11 19:12:04 +02:00
#endif
2018-11-20 16:48:35 +01:00
// initialize sensors
2019-03-19 00:02:35 +01:00
#if (HAS_SENSORS)
2018-11-20 16:48:35 +01:00
strcat_P(features, " SENS");
sensor_init();
#endif
2018-08-11 19:12:04 +02:00
// initialize LoRa
2019-03-19 00:02:35 +01:00
#if (HAS_LORA)
2018-08-11 19:12:04 +02:00
strcat_P(features, " LORA");
2018-11-03 20:29:02 +01:00
assert(lora_stack_init() == ESP_OK);
2019-02-27 00:52:27 +01:00
#endif
2018-08-11 19:12:04 +02:00
// initialize SPI
2018-08-03 23:50:04 +02:00
#ifdef HAS_SPI
2018-08-11 19:12:04 +02:00
strcat_P(features, " SPI");
assert(spi_init() == ESP_OK);
2019-02-27 00:52:27 +01:00
#endif
2018-08-03 23:50:04 +02:00
2019-03-13 21:15:28 +01:00
#if (VENDORFILTER)
2019-05-25 15:31:20 +02:00
strcat_P(features, " FILTER");
2018-06-10 22:46:13 +02:00
#endif
2018-07-23 13:20:06 +02:00
// initialize display
2018-06-10 22:46:13 +02:00
#ifdef HAS_DISPLAY
2018-06-17 11:40:52 +02:00
strcat_P(features, " OLED");
DisplayIsOn = cfg.screenon;
2019-02-02 10:35:20 +01:00
init_display(PRODUCTNAME, PROGVERSION); // note: blocking call
2018-06-10 22:46:13 +02:00
#endif
// initialize matrix display
#ifdef HAS_MATRIX_DISPLAY
strcat_P(features, " LED_MATRIX");
MatrixDisplayIsOn = cfg.screenon;
2019-05-30 13:00:24 +02:00
init_matrix_display(); // note: blocking call
#endif
2018-06-17 11:40:52 +02:00
// show payload encoder
#if PAYLOAD_ENCODER == 1
2018-08-02 11:33:02 +02:00
strcat_P(features, " PLAIN");
2018-06-17 11:40:52 +02:00
#elif PAYLOAD_ENCODER == 2
2018-08-02 11:33:02 +02:00
strcat_P(features, " PACKED");
2018-06-17 11:40:52 +02:00
#elif PAYLOAD_ENCODER == 3
2018-08-02 11:33:02 +02:00
strcat_P(features, " LPPDYN");
2018-07-22 16:12:46 +02:00
#elif PAYLOAD_ENCODER == 4
2018-08-02 11:33:02 +02:00
strcat_P(features, " LPPPKD");
2018-06-17 11:40:52 +02:00
#endif
// initialize RTC
2019-02-02 10:35:20 +01:00
#ifdef HAS_RTC
strcat_P(features, " RTC");
assert(rtc_init());
#endif
2019-02-02 10:35:20 +01:00
#if defined HAS_DCF77
strcat_P(features, " DCF77");
#endif
#if defined HAS_IF482
strcat_P(features, " IF482");
#endif
2019-04-13 17:39:08 +02:00
#if (WIFICOUNTER)
strcat_P(features, " WIFI");
// start wifi in monitor mode and start channel rotation timer
ESP_LOGI(TAG, "Starting Wifi...");
2018-07-15 14:28:05 +02:00
wifi_sniffer_init();
// initialize salt value using esp_random() called by random() in
2018-09-15 18:59:20 +02:00
// arduino-esp32 core. Note: do this *after* wifi has started, since
// function gets it's seed from RF noise
2018-09-23 22:12:10 +02:00
get_salt(); // get new 16bit for salting hashes
2019-04-13 17:39:08 +02:00
#else
// switch off wifi
WiFi.mode(WIFI_OFF);
esp_wifi_stop();
esp_wifi_deinit();
#endif
2018-09-21 18:23:34 +02:00
// start state machine
2019-01-28 00:38:31 +01:00
ESP_LOGI(TAG, "Starting Interrupt Handler...");
xTaskCreatePinnedToCore(irqHandler, // task function
"irqhandler", // name of task
2018-12-22 21:40:43 +01:00
4096, // stack size of task
(void *)1, // parameter of the task
2019-04-07 12:27:38 +02:00
2, // priority of the task
&irqHandlerTask, // task handle
1); // CPU core
2018-09-22 13:43:12 +02:00
2019-03-13 21:15:28 +01:00
// initialize BME sensor (BME280/BME680)
#if (HAS_BME)
2019-03-08 18:13:51 +01:00
#ifdef HAS_BME680
2019-03-13 21:15:28 +01:00
strcat_P(features, " BME680");
#elif defined HAS_BME280
2019-03-08 18:13:51 +01:00
strcat_P(features, " BME280");
2019-03-13 21:15:28 +01:00
#endif
2018-12-26 13:00:32 +01:00
if (bme_init()) {
2019-03-07 22:17:28 +01:00
ESP_LOGI(TAG, "Starting BME sensor...");
2018-12-26 13:00:32 +01:00
xTaskCreatePinnedToCore(bme_loop, // task function
"bmeloop", // name of task
2019-01-06 19:41:42 +01:00
2048, // stack size of task
2018-12-26 13:00:32 +01:00
(void *)1, // parameter of the task
1, // priority of the task
2018-12-26 13:00:32 +01:00
&BmeTask, // task handle
1); // CPU core
}
#endif
2019-03-03 13:07:48 +01:00
// starting timers and interrupts
2019-01-28 00:38:31 +01:00
assert(irqHandlerTask != NULL); // has interrupt handler task started?
ESP_LOGI(TAG, "Starting Timers...");
2019-03-03 13:07:48 +01:00
// display interrupt
#ifdef HAS_DISPLAY
2019-03-03 13:07:48 +01:00
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up
displayIRQ = timerBegin(0, 80, true);
timerAttachInterrupt(displayIRQ, &DisplayIRQ, true);
timerAlarmWrite(displayIRQ, DISPLAYREFRESH_MS * 1000, true);
2019-03-03 12:57:00 +01:00
timerAlarmEnable(displayIRQ);
#endif
2019-03-03 13:07:48 +01:00
// LED Matrix display interrupt
#ifdef HAS_MATRIX_DISPLAY
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 3, count up
matrixDisplayIRQ = timerBegin(3, 80, true);
timerAttachInterrupt(matrixDisplayIRQ, &MatrixDisplayIRQ, true);
timerAlarmWrite(matrixDisplayIRQ, MATRIX_DISPLAY_SCAN_US, true);
timerAlarmEnable(matrixDisplayIRQ);
#endif
2019-05-03 20:24:42 +02:00
// initialize button
#ifdef HAS_BUTTON
strcat_P(features, " BTN_");
#ifdef BUTTON_PULLUP
strcat_P(features, "PU");
#else
strcat_P(features, "PD");
#endif // BUTTON_PULLUP
button_init(HAS_BUTTON);
#endif // HAS_BUTTON
// gps buffer read interrupt
#if (HAS_GPS)
gpsIRQ = timerBegin(2, 80, true);
timerAttachInterrupt(gpsIRQ, &GpsIRQ, true);
2019-04-15 13:46:58 +02:00
timerAlarmWrite(gpsIRQ, 300 * 1000, true);
timerAlarmEnable(gpsIRQ);
#endif
// cyclic function interrupts
2019-03-03 13:07:48 +01:00
sendcycler.attach(SENDCYCLE * 2, sendcycle);
housekeeper.attach(HOMECYCLE, housekeeping);
2019-03-13 21:15:28 +01:00
#if (TIME_SYNC_INTERVAL)
2019-04-07 16:13:04 +02:00
#if (!(TIME_SYNC_LORAWAN) && !(TIME_SYNC_LORASERVER) && !defined HAS_GPS && \
!defined HAS_RTC)
2019-03-31 15:32:22 +02:00
#warning you did not specify a time source, time will not be synched
#endif
2019-04-07 16:13:04 +02:00
#if (defined HAS_IF482 || defined HAS_DCF77)
ESP_LOGI(TAG, "Starting Clock Controller...");
clock_init();
#endif
2019-04-08 21:22:54 +02:00
#if (TIME_SYNC_LORASERVER)
2019-04-13 13:59:30 +02:00
timesync_init(); // create loraserver time sync task
2019-04-08 21:22:54 +02:00
#endif
ESP_LOGI(TAG, "Starting Timekeeper...");
2019-04-13 13:59:30 +02:00
assert(timepulse_init()); // setup pps timepulse
timepulse_start(); // starts pps and cyclic time sync
2019-04-07 16:13:04 +02:00
#endif // TIME_SYNC_INTERVAL
2019-05-03 20:24:42 +02:00
// show compiled features
ESP_LOGI(TAG, "Features:%s", features);
} // setup()
void loop() {
2019-04-07 12:27:38 +02:00
while (1) {
2019-03-19 00:02:35 +01:00
#if (HAS_LORA)
2018-10-03 16:24:45 +02:00
os_runloop_once(); // execute lmic scheduled jobs and events
2019-04-07 12:27:38 +02:00
#else
2018-12-19 12:32:25 +01:00
delay(2); // yield to CPU
2019-04-07 12:27:38 +02:00
#endif
}
}