diff --git a/README.md b/README.md index 1cf6607c..4cdf2f2d 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ Output of sensor and peripheral data is internally switched by a bitmask registe # Power saving mode -Paxcounter supports a battery friendly power saving mode. In this mode the device enters deep sleep, after all data is polled from all sensors and the dataset is completeley sent through all user configured channels (LORAWAN / SPI / MQTT). Set *#define SLEEPCYCLE* in paxcounter.conf to enable power saving mode and to specify the duration of a sleep cycle. Power consumption in deep sleep mode depends on your hardware, i.e. if on board peripherals can be switched off or set to a chip specific sleep mode either by MCU or by power management unit (PMU) as found on TTGO T-BEAM v1.0/V1.1. See *power.cpp* for power management, and *reset.cpp* for sleep and wakeup logic. +Paxcounter supports a battery friendly power saving mode. In this mode the device enters deep sleep, after all data is polled from all sensors and the dataset is completeley sent through all user configured channels (LORAWAN / SPI / MQTT / SD-Card). Set *#define SLEEPCYCLE* in paxcounter.conf to enable power saving mode and to specify the duration of a sleep cycle. Power consumption in deep sleep mode depends on your hardware, i.e. if on board peripherals can be switched off or set to a chip specific sleep mode either by MCU or by power management unit (PMU) as found on TTGO T-BEAM v1.0/V1.1. See *power.cpp* for power management, and *reset.cpp* for sleep and wakeup logic. # Time sync @@ -216,22 +216,13 @@ Paxcounter can be used to sync a wall clock which has a DCF77 or IF482 time tele This describes how to set up a mobile PaxCounter:
Follow all steps so far for preparing the device, selecting the packed payload format. In `paxcounter.conf` set PAYLOAD_OPENSENSEBOX to 1. Register a new sensebox on https://opensensemap.org/. In the sensor configuration select "TheThingsNetwork" and set decoding profile to "LoRa serialization". Enter your TTN Application and Device ID. Setup decoding option using `[{"decoder":"latLng"},{"decoder":"uint16",sensor_id":"yoursensorid"}]` -# Covid-19 Exposure Notification System beacon detection (currently NOT working with v3.0.x, use v2.4.x for this feature) - -Bluetooth low energy service UUID 0xFD6F, used by Google/Apple COVID-19 Exposure Notification System, can be monitored and counted. By comparing with the total number of observed devices this gives an indication how many people staying in proximity are using Apps for tracing COVID-19 exposures, e.g. in Germany the "Corona Warn App". To achive best results with this funcion, use following settings in `paxcounter.conf`: - - #define COUNT_ENS 1 // enable ENS monitoring function - #define BLECOUNTER 1 // enable bluetooth sniffing - #define WIFICOUNTER 0 // disable wifi sniffing (improves BLE scan speed) - #define HAS_SENSOR_1 1 // optional, in board's hal file: transmit ENS counter data to server - # SD-card -Data can be stored on an SD-card if one is availabe. Simply choose the file in src/hal and add the following lines to your hal-file: +Data can be stored on SD-card if the board provides an SD card interface, either with SPI or MMC mode. To enable this feature, specify interface mode and hardware pins in board's hal file (src/hal/): - #define HAS_SDCARD 1 // SD-card-reader/writer, using SPI interface + #define HAS_SDCARD 1 // SD-card interface, using SPI mode OR - #define HAS_SDCARD 2 // SD-card-reader/writer, using SDMMC interface + #define HAS_SDCARD 2 // SD-card interface, using MMC mode // Pins for SPI interface #define SDCARD_CS (13) // fill in the correct numbers for your board @@ -239,31 +230,24 @@ Data can be stored on an SD-card if one is availabe. Simply choose the file in s #define SDCARD_MISO (2) #define SDCARD_SCLK (14) -Please choose the correct number for the connection of the reader/writer. - -This is an example of a board with SD-card: https://www.aliexpress.com/item/32990008126.html -In this case you take the file src/hal/ttgov21new.h and add the lines given above (numbers given are for this board). +This is an example of a board with MMC SD-card interface: https://www.aliexpress.com/item/32915894264.html. For this board use file src/hal/ttgov21new.h and add the lines given above. Another approach would be this tiny board: https://www.aliexpress.com/item/32424558182.html (needs 5V). -In this case you choose the correct file for your ESP32-board in the src/hal-directory and add the lines given above to the correct h-file. Please correct the numbers given in the example to the numbers used corresponding to your wiring. +In this case you choose the correct file for your ESP32-board in the src/hal-directory and add the lines given above. Edit the pin numbers given in the example, according to your wiring. -Some hints: -These cheap devices often handle SD-cards up to 32GB, not bigger ones. They can handle files in the old DOS-way, to say the filenames are in the 8.3-format. And they often cannot handle subdirectories. +Data is written on SD-card to a single file. After 3 write operations the data is flushed to the disk to minimize flash write cycles. Thus, up to the last 3 records of data will get lost when the PAXCOUNTER looses power during operation. -The software included here writes data in a file named PAXCOUNT.xx, where xx can range from 00 to 99. The software starts with 00, checks to see if such a file already exists and if yes it will continue with the next number (up to 99 - in this case it will return no sd-card). So an existing file will not be overwritten. +Format of the resulting file is CSV, thus easy import in LibreOffice, Excel, Influx, etc. Each record contains timestamp (in ISO8601 format), paxcount (wifi and ble) and battery voltage (optional). Voltage is logged if the device has a battery voltage sensor (to be configured in board hal file). -The data is written to the card and after 3 write-operations the data is flushed to the disk. So maybe the last 3 minutes of data get lost when you disconnect the PAXCOUNTER from power. +File contents example: -And finally: this is the data written to the disk: - - date, time, wifi, bluet - 00.00.1970,00:01:09,2,0 - 00.00.1970,00:02:09,1,0 - 00.00.1970,00:03:09,2,0 - -Format of the data is CSV, which can easily imported into LibreOffice, Excel, ..... - -If you want to change this please look into src/sdcard.cpp and include/sdcard.h. + timestamp,wifi,ble[,voltage] + 2022-01-30T21:12:41Z,11,25[,4100] + 2022-01-30T21:14:24Z,10,21[,4070] + 2022-01-30T21:16:08Z,12,26[,4102] + 2022-01-30T21:17:52Z,11,26[,4076] + +If you want to change this, modify src/sdcard.cpp and include/sdcard.h. # Integration into "The Things Stack Community Edition" aka "The Things Stack V3" @@ -383,7 +367,7 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering. **Ports #10, #11, #12:** User sensor data - Format is specified by user in function `sensor_read(uint8_t sensor)`, see `src/sensor.cpp`. Port #10 is also used for ENS counter (2 bytes = 16 bit), if ENS is compiled AND ENS data transfer is enabled + Format is specified by user in function `sensor_read(uint8_t sensor)`, see `src/sensor.cpp`. # Remote control @@ -503,7 +487,7 @@ Send for example `83` `86` as Downlink on Port 2 to get battery status and time/ 0x02 = RESERVED_DATA 0x04 = MEMS_DATA 0x08 = GPS_DATA - 0x10 = SENSOR_1_DATA (also ENS counter) + 0x10 = SENSOR_1_DATA 0x20 = SENSOR_2_DATA 0x40 = SENSOR_3_DATA 0x80 = BATT_DATA @@ -524,10 +508,9 @@ Send for example `83` `86` as Downlink on Port 2 to get battery status and time/ 0 = disabled 1 = enabled [default] -0x18 set ENS counter on/off +0x18 reserved - 0 = disabled [default] - 1 = enabled + unused, does nothing 0x19 set sleep cycle @@ -621,4 +604,4 @@ Thanks to - [terrillmoore](https://github.com/mcci-catena) for maintaining the LMIC for arduino LoRaWAN stack - [sbamueller](https://github.com/sbamueller) for writing the tutorial in Make Magazine - [Stefan](https://github.com/nerdyscout) for paxcounter opensensebox integration -- [August Quint](https://github.com/AugustQu) for adding SD card data logger, SDS011 and ENS support +- [August Quint](https://github.com/AugustQu) for adding SD card data logger and SDS011 support diff --git a/include/corona.h b/include/corona.h deleted file mode 100644 index 9af0d314..00000000 --- a/include/corona.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _CORONA_h -#define _CORONA_H - -// inspired by https://github.com/kmetz/BLEExposureNotificationBeeper -// (c) by Kaspar Metz -// modified for use in the Paxcounter by AQ - -#include "globals.h" -#include - -bool cwa_init(void); -void cwa_mac_add(uint16_t hashedmac); -void cwa_clear(void); -uint16_t cwa_report(void); - -#endif diff --git a/include/display.h b/include/display.h index 2b00aa44..70187893 100644 --- a/include/display.h +++ b/include/display.h @@ -5,10 +5,7 @@ #include "cyclic.h" #include "qrcode.h" #include "power.h" - -#if (COUNT_ENS) -#include "corona.h" -#endif +#include "timekeeper.h" #if (HAS_DISPLAY) == 1 #include diff --git a/include/globals.h b/include/globals.h index a3a60341..9b141b09 100644 --- a/include/globals.h +++ b/include/globals.h @@ -71,7 +71,6 @@ typedef struct __attribute__((packed)) { uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4) uint8_t rgblum; // RGB Led luminosity (0..100%) uint8_t payloadmask; // bitswitches for payload data - uint8_t enscount; // 0=disabled 1= enabled #ifdef HAS_BME680 uint8_t @@ -111,6 +110,5 @@ typedef struct { } sdsStatus_t; extern char clientId[20]; // unique clientID -extern time_t _COMPILETIME; // epoch build time #endif \ No newline at end of file diff --git a/include/gpsread.h b/include/gpsread.h index fe204bea..95cd1afa 100644 --- a/include/gpsread.h +++ b/include/gpsread.h @@ -5,13 +5,10 @@ #include #include "timekeeper.h" -#ifdef GPS_I2C // Needed for reading from I2C Bus -#include +#ifndef GPS_BAUDRATE +#define GPS_BAUDRATE 115200UL #endif -#define NMEA_FRAME_SIZE 82 // NEMA has a maxium of 82 bytes per record -#define NMEA_COMPENSATION_FACTOR 480 // empiric for Ublox Neo 6M - extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe extern TaskHandle_t GpsTask; diff --git a/include/irqhandler.h b/include/irqhandler.h index 8b14b293..eacbd35f 100644 --- a/include/irqhandler.h +++ b/include/irqhandler.h @@ -24,7 +24,7 @@ void irqHandler(void *pvParameters); void mask_user_IRQ(); void unmask_user_IRQ(); -void doIRQ(int irq); +void IRAM_ATTR doIRQ(int irq); extern TaskHandle_t irqHandlerTask; diff --git a/include/libpax_helpers.h b/include/libpax_helpers.h index 74be26a4..aee1e1c4 100644 --- a/include/libpax_helpers.h +++ b/include/libpax_helpers.h @@ -8,6 +8,6 @@ void init_libpax(void); -extern uint16_t volatile libpax_macs_ble, libpax_macs_wifi; // libpax values +extern struct count_payload_t count_from_libpax; // libpax count storage #endif \ No newline at end of file diff --git a/include/main.h b/include/main.h index a0772b03..824b020e 100644 --- a/include/main.h +++ b/include/main.h @@ -7,6 +7,8 @@ #include // needed for coex version display #include // needed for wifi init / deinit +#include + #include "globals.h" #include "reset.h" #include "i2c.h" @@ -18,9 +20,7 @@ #include "sensor.h" #include "lorawan.h" #include "timekeeper.h" -#include "corona.h" #include "boot.h" -#include "libpax_helpers.h" #include "power.h" #include "antenna.h" diff --git a/include/rcommand.h b/include/rcommand.h index 0cdb23c6..d842fdef 100644 --- a/include/rcommand.h +++ b/include/rcommand.h @@ -3,6 +3,7 @@ #include +#include "libpax_helpers.h" #include "senddata.h" #include "cyclic.h" #include "configmanager.h" diff --git a/include/reset.h b/include/reset.h index bffff1bc..6ce2661e 100644 --- a/include/reset.h +++ b/include/reset.h @@ -8,6 +8,8 @@ #include "lorawan.h" #include "display.h" #include "power.h" +#include "sdcard.h" +#include "sds011read.h" void reset_rtc_vars(void); void do_reset(bool warmstart); diff --git a/include/rtctime.h b/include/rtctime.h index d4d64935..3f75eb37 100644 --- a/include/rtctime.h +++ b/include/rtctime.h @@ -12,7 +12,7 @@ extern RtcDS3231 Rtc; // make RTC instance globally available uint8_t rtc_init(void); uint8_t set_rtctime(time_t t); void sync_rtctime(void); -time_t get_rtctime(void); +time_t get_rtctime(uint16_t *msec); float get_rtctemp(void); #endif // _RTCTIME_H \ No newline at end of file diff --git a/include/sdcard.h b/include/sdcard.h index 5c34dc11..25fcf2c4 100644 --- a/include/sdcard.h +++ b/include/sdcard.h @@ -1,13 +1,13 @@ #ifndef _SDCARD_H #define _SDCARD_H -#include +#include "globals.h" #include #include #if (HAS_SDCARD) #if HAS_SDCARD == 1 -#include +#include #elif HAS_SDCARD == 2 #include #else @@ -54,14 +54,15 @@ #define SDCARD_DATA3 13 #endif -#define SDCARD_FILE_NAME "/paxcount.%02d" -#define SDCARD_FILE_HEADER "date, time, wifi, bluet" +#define SDCARD_FILE_NAME clientId +#define SDCARD_FILE_HEADER "timestamp,wifi,ble" -#if (COUNT_ENS) -#define SDCARD_FILE_HEADER_CWA ",cwa" +#if (defined BAT_MEASURE_ADC || defined HAS_PMU) +#define SDCARD_FILE_HEADER_VOLTAGE ",voltage" #endif -bool sdcard_init(void); +bool sdcard_init(bool create = true); +void sdcard_close(void); void sdcardWriteData(uint16_t, uint16_t, uint16_t = 0); #endif // _SDCARD_H diff --git a/include/sds011read.h b/include/sds011read.h index f49c34f0..f1b874d3 100644 --- a/include/sds011read.h +++ b/include/sds011read.h @@ -1,15 +1,24 @@ #ifndef _SDS011READ_H #define _SDS011READ_H -#include +#include #include "globals.h" #define SDCARD_FILE_HEADER_SDS011 ", PM10,PM25" +// use original pins from HardwareSerial if none defined +#ifndef SDS_TX +#define SDS_TX -1 +#endif +#ifndef SDS_RX +#define SDS_RX -1 +#endif + +extern bool isSDS011Active; + bool sds011_init(); void sds011_loop(); void sds011_sleep(void); void sds011_wakeup(void); void sds011_store(sdsStatus_t *sds_store); - #endif // _SDS011READ_H diff --git a/include/senddata.h b/include/senddata.h index 4ae83018..ff0a382b 100644 --- a/include/senddata.h +++ b/include/senddata.h @@ -1,7 +1,6 @@ #ifndef _SENDDATA_H #define _SENDDATA_H -#include "libpax_helpers.h" #include "spislave.h" #include "mqttclient.h" #include "cyclic.h" @@ -10,18 +9,13 @@ #include "display.h" #include "sdcard.h" -#if (COUNT_ENS) -#include "corona.h" -#endif - -extern struct count_payload_t count_from_libpax; - void SendPayload(uint8_t port); void sendData(void); void checkSendQueues(void); void flushQueues(void); bool allQueuesEmtpy(void); -void setSendIRQ(TimerHandle_t xTimer = NULL); +void setSendIRQ(TimerHandle_t xTimer); +void setSendIRQ(void); void initSendDataTimer(uint8_t sendcycle); #endif // _SENDDATA_H_ diff --git a/include/timekeeper.h b/include/timekeeper.h index 8eb184b4..bb97a043 100644 --- a/include/timekeeper.h +++ b/include/timekeeper.h @@ -10,8 +10,8 @@ #include "dcf77.h" #include "esp_sntp.h" -#define SECS_YR_2000 (946684800UL) // the time at the start of y2k -#define GPS_UTC_DIFF 315964800UL // seconds diff between gps and utc epoch +#define SECS_YR_2000 (946684800UL) // the time at the start of y2k +#define GPS_UTC_DIFF 315964800UL // seconds diff between gps and utc epoch #define LEAP_SECS_SINCE_GPSEPOCH 18UL // state of 2021 enum timesource_t { _gps, _rtc, _lora, _unsynced, _set }; @@ -20,22 +20,22 @@ extern const char timeSetSymbols[]; extern Ticker timesyncer; extern timesource_t timeSource; extern TaskHandle_t ClockTask; -extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC +extern DRAM_ATTR bool TimePulseTick; // 1sec pps flag set by GPS or RTC +extern DRAM_ATTR unsigned long lastPPS; extern hw_timer_t *ppsIRQ; void IRAM_ATTR CLOCKIRQ(void); +void IRAM_ATTR GPSIRQ(void); void clock_init(void); void clock_loop(void *pvParameters); -void timepulse_start(void); void setTimeSyncIRQ(void); uint8_t timepulse_init(void); bool timeIsValid(time_t const t); void calibrateTime(void); void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, timesource_t mytimesource); -time_t compileTime(const String compile_date); +time_t compileTime(void); time_t mkgmtime(const struct tm *ptm); TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPins); - #endif // _timekeeper_H \ No newline at end of file diff --git a/platformio_orig.ini b/platformio_orig.ini index 100ede8a..6baf22c9 100644 --- a/platformio_orig.ini +++ b/platformio_orig.ini @@ -48,7 +48,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I [common] ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" -release_version = 3.1.0 +release_version = 3.2.0 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 3 @@ -56,7 +56,7 @@ extra_scripts = pre:build.py otakeyfile = ota.conf lorakeyfile = loraconf.h lmicconfigfile = lmic_config.h -platform_espressif32 = espressif32@3.4.0 +platform_espressif32 = espressif32@3.5.0 monitor_speed = 115200 upload_speed = 115200 ; set by build.py and taken from hal file display_library = ; set by build.py and taken from hal file @@ -77,7 +77,7 @@ lib_deps_sensors = adafruit/Adafruit BME280 Library @ ^2.2.1 adafruit/Adafruit BMP085 Library @ ^1.2.0 boschsensortec/BSEC Software Library @ 1.6.1480 - https://github.com/ricki-z/SDS011.git + https://github.com/cyberman54/sds-dust-sensors-arduino-library.git lib_deps_basic = https://github.com/dbSuS/libpax.git @ ^1.0.0 https://github.com/SukkoPera/Arduino-Rokkit-Hash.git @@ -85,7 +85,6 @@ lib_deps_basic = makuna/RTC @ ^2.3.5 spacehuhn/SimpleButton lewisxhe/AXP202X_Library @ ^1.1.3 - geeksville/esp32-micro-sdcard @ ^0.1.1 256dpi/MQTT @ ^2.4.8 lib_deps_all = ${common.lib_deps_basic} @@ -133,4 +132,4 @@ upload_protocol = esptool [env:dev] upload_protocol = esptool build_type = debug -platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream \ No newline at end of file +platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index f338e6df..7230fb46 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -84,11 +84,6 @@ function Decoder(bytes, port) { } } - if (port === 10) { - // ENS count - return decode(bytes, [uint16], ['ens']); - } - } diff --git a/src/TTNv3/packed_decodeUplink.js b/src/TTNv3/packed_decodeUplink.js index a010f3dc..94c1ec8b 100644 --- a/src/TTNv3/packed_decodeUplink.js +++ b/src/TTNv3/packed_decodeUplink.js @@ -90,11 +90,6 @@ function decodeUplink(input) { data = decode(input.bytes, [uint32, uint8], ['time', 'timestatus']); } } - - if (input.fPort === 10) { - // ENS count - data = decode(input.bytes, [uint16], ['ens']); - } data.bytes = input.bytes; // comment out if you do not want to include the original payload data.port = input.fPort; // comment out if you do not want to inlude the port diff --git a/src/TTNv3/plain_decodeUplink.js b/src/TTNv3/plain_decodeUplink.js index d19feb48..0b1b8c23 100644 --- a/src/TTNv3/plain_decodeUplink.js +++ b/src/TTNv3/plain_decodeUplink.js @@ -84,13 +84,6 @@ function decodeUplink(input) { } } - if (input.fPort === 10) { - var i = 0; - if (input.bytes.length >= 2) { - data.ens = (input.bytes[i++] << 8) | input.bytes[i++]; - } - } - if (data.hdop) { data.hdop /= 100; data.latitude /= 1000000; diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 7de8d127..6112444d 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -6,12 +6,6 @@ // Local logging tag static const char TAG[] = __FILE__; -// default settings for device data to be sent -#define PAYLOADMASK \ - ((GPS_DATA | MEMS_DATA | COUNT_DATA | SENSOR1_DATA | SENSOR2_DATA | \ - SENSOR3_DATA) & \ - (~BATT_DATA) & (~RESERVED_DATA)) - // namespace for device runtime preferences #define DEVCONFIG "paxcntcfg" @@ -57,7 +51,6 @@ static void defaultConfig(configData_t *myconfig) { myconfig->wifiant = 0; // 0=internal, 1=external (for LoPy/LoPy4) myconfig->rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%) myconfig->payloadmask = PAYLOADMASK; // payloads as defined in default - myconfig->enscount = COUNT_ENS; // 0=disabled, 1=enabled #ifdef HAS_BME680 // initial BSEC state for BME680 sensor diff --git a/src/corona.cpp b/src/corona.cpp deleted file mode 100644 index bd20fb17..00000000 --- a/src/corona.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// routines for counting the number of devices which advertise Exposure -// Notification Service e.g. "Corona Warn App" in Germany - -// copied from https://github.com/kmetz/BLEExposureNotificationBeeper -// (c) by Kaspar Metz -// modified for use in the Paxcounter by AQ - -#if (COUNT_ENS) && !(BLECOUNTER) -#warning ENS-Counter needs Bluetooth, but Bluetooth compile option is disabled -#endif - -#if (COUNT_ENS) - -// Local logging tag -static const char TAG[] = __FILE__; - -#define BT_BD_ADDR_HEX(addr) \ - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] - -#include "corona.h" - -// When to forget old senders ** currently not used ** -#define FORGET_AFTER_MINUTES 2 - -// array of timestamps for seen notifiers: hash -> timestamp[ms] -static std::map cwaSeenNotifiers; - -// Remove notifiers last seen over FORGET_AFTER_MINUTES ago. -void cwa_clear() { -#ifdef VERBOSE - ESP_LOGV(TAG, "CWA: forget old notifier: %d", cwaSeenNotifiers.size()); - for (auto const ¬ifier : cwaSeenNotifiers) { - ESP_LOGD(TAG, "CWA forget <%04X>", notifier.first); - // } - } -#endif - // clear everything, otherwise we would count the same device again, as in the - // next cycle it likely will advertise with a different hash-value - cwaSeenNotifiers.clear(); -} - -// return the total number of devices seen advertising ENS -uint16_t cwa_report(void) { return cwaSeenNotifiers.size(); } - -bool cwa_init(void) { - ESP_LOGD(TAG, "init BLE-scanner for ENS"); - return true; -} - -void cwa_mac_add(uint16_t hashedmac) { - cwaSeenNotifiers[hashedmac] = millis(); // hash last seen at .... -} - -#endif diff --git a/src/cyclic.cpp b/src/cyclic.cpp index d197e234..385f9afe 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -9,10 +9,6 @@ static const char TAG[] = __FILE__; Ticker cyclicTimer; -#if (HAS_SDS011) -extern boolean isSDS011Active; -#endif - void setCyclicIRQ() { xTaskNotify(irqHandlerTask, CYCLIC_IRQ, eSetBits); } // do all housekeeping @@ -22,44 +18,62 @@ void doHousekeeping() { if ((RTC_runmode == RUNMODE_UPDATE) || (RTC_runmode == RUNMODE_MAINTENANCE)) do_reset(true); // warmstart - // heap and task storage debugging + // try to get time if we don't yet have a recent timesource + if (timeSource == _unsynced || timeSource == _set) + calibrateTime(); + + // print heap and task storage information ESP_LOGD(TAG, "Heap: Free:%d, Min:%d, Size:%d, Alloc:%d, StackHWM:%d", ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getHeapSize(), ESP.getMaxAllocHeap(), uxTaskGetStackHighWaterMark(NULL)); - ESP_LOGD(TAG, "IRQhandler %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(irqHandlerTask), - eTaskGetState(irqHandlerTask)); - ESP_LOGD(TAG, "Rcommand interpreter %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(rcmdTask), eTaskGetState(rcmdTask)); + + if (irqHandlerTask != NULL) + ESP_LOGD(TAG, "IRQhandler %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(irqHandlerTask), + eTaskGetState(irqHandlerTask)); + if (rcmdTask != NULL) + ESP_LOGD(TAG, "Rcommand interpreter %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(rcmdTask), eTaskGetState(rcmdTask)); + #if (HAS_LORA) - ESP_LOGD(TAG, "LMiCtask %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(lmicTask), eTaskGetState(lmicTask)); - ESP_LOGD(TAG, "Lorasendtask %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(lorasendTask), - eTaskGetState(lorasendTask)); + if (lmicTask != NULL) + ESP_LOGD(TAG, "LMiCtask %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(lmicTask), eTaskGetState(lmicTask)); + if (lorasendTask != NULL) + ESP_LOGD(TAG, "Lorasendtask %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(lorasendTask), + eTaskGetState(lorasendTask)); #endif + #if (HAS_GPS) - ESP_LOGD(TAG, "Gpsloop %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(GpsTask), eTaskGetState(GpsTask)); + if (GpsTask != NULL) + ESP_LOGD(TAG, "Gpsloop %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(GpsTask), eTaskGetState(GpsTask)); #endif + #ifdef HAS_SPI - ESP_LOGD(TAG, "spiloop %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(spiTask), eTaskGetState(spiTask)); + if (spiTask != NULL) + ESP_LOGD(TAG, "spiloop %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(spiTask), eTaskGetState(spiTask)); #endif + #ifdef HAS_MQTT - ESP_LOGD(TAG, "MQTTloop %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(mqttTask), eTaskGetState(mqttTask)); + if (mqttTask != NULL) + ESP_LOGD(TAG, "MQTTloop %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(mqttTask), eTaskGetState(mqttTask)); #endif #if (defined HAS_DCF77 || defined HAS_IF482) - ESP_LOGD(TAG, "Clockloop %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(ClockTask), eTaskGetState(ClockTask)); + if (ClockTask != NULL) + ESP_LOGD(TAG, "Clockloop %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(ClockTask), eTaskGetState(ClockTask)); #endif #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) - ESP_LOGD(TAG, "LEDloop %d bytes left | Taskstate = %d", - uxTaskGetStackHighWaterMark(ledLoopTask), - eTaskGetState(ledLoopTask)); + if (ledLoopTask != NULL) + ESP_LOGD(TAG, "LEDloop %d bytes left | Taskstate = %d", + uxTaskGetStackHighWaterMark(ledLoopTask), + eTaskGetState(ledLoopTask)); #endif // read battery voltage into global variable @@ -106,10 +120,8 @@ void doHousekeeping() { #if (HAS_SDS011) if (isSDS011Active) { - ESP_LOGD(TAG, "SDS011: go to sleep"); sds011_loop(); } else { - ESP_LOGD(TAG, "SDS011: wakeup"); sds011_wakeup(); } #endif diff --git a/src/dcf77.cpp b/src/dcf77.cpp index fd59cb51..8b30dcf4 100644 --- a/src/dcf77.cpp +++ b/src/dcf77.cpp @@ -51,18 +51,17 @@ void DCF77_Pulse(uint8_t bit) { // helper function to convert decimal to bcd digit uint64_t dec2bcd(uint8_t const dec, uint8_t const startpos, - uint8_t const endpos, uint8_t *odd_parity) { + uint8_t const endpos, uint8_t *parity) { - uint8_t data = (dec < 10) ? dec : ((dec / 10) << 4) + (dec % 10); + uint8_t data = dec < 10 ? dec : ((dec / 10) << 4) + dec % 10; uint64_t bcd = 0; - *odd_parity = 0; + *parity = 0; for (uint8_t i = startpos; i <= endpos; i++) { - bcd += (data & 1) ? set_dcfbit(i) : 0; - *odd_parity += (data & 1); + bcd += data & 1 ? set_dcfbit(i) : 0; + *parity ^= data & 1; data >>= 1; } - *odd_parity %= 2; return bcd; } @@ -96,14 +95,14 @@ uint64_t DCF77_Frame(const struct tm t) { // DATE (36..58) frame += dec2bcd(t.tm_mday, 36, 41, &parity); - parity_sum += parity; + parity_sum ^= parity; frame += dec2bcd((t.tm_wday == 0) ? 7 : t.tm_wday, 42, 44, &parity); - parity_sum += parity; + parity_sum ^= parity; frame += dec2bcd(t.tm_mon + 1, 45, 49, &parity); - parity_sum += parity; + parity_sum ^= parity; frame += dec2bcd(t.tm_year + 1900 - 2000, 50, 57, &parity); - parity_sum += parity; - frame += parity_sum % 2 ? set_dcfbit(58) : 0; + parity_sum ^= parity; + frame += parity_sum ? set_dcfbit(58) : 0; return frame; diff --git a/src/display.cpp b/src/display.cpp index fdf70904..692b352d 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -174,16 +174,10 @@ void dp_init(bool verbose) { void dp_refresh(bool nextPage) { - // update counter values from libpax - libpax_counter_count(&count_from_libpax); - #ifndef HAS_BUTTON static uint32_t framecounter = 0; #endif - // update histogram - dp_plotCurve(count_from_libpax.pax, false); - // if display is switched off we don't refresh it to relax cpu if (!DisplayIsOn && (DisplayIsOn == cfg.screenon)) return; @@ -207,7 +201,6 @@ void dp_refresh(bool nextPage) { #endif dp_drawPage(nextPage); - dp_dump(displaybuf); I2C_MUTEX_UNLOCK(); // release i2c bus access @@ -219,6 +212,7 @@ void dp_drawPage(bool nextpage) { // write display content to display buffer // nextpage = true -> flip 1 page + struct count_payload_t count; // libpax count storage static uint8_t DisplayPage = 0; char timeState, strftime_buf[64]; time_t now; @@ -233,6 +227,9 @@ void dp_drawPage(bool nextpage) { dp_clear(); } + // update counter values from libpax + libpax_counter_count(&count); + // cursor home dp_setTextCursor(0, 0); @@ -240,7 +237,7 @@ void dp_drawPage(bool nextpage) { // display number of unique macs total Wifi + BLE if (DisplayPage < 5) { dp_setFont(MY_FONT_STRETCHED); - dp_printf("%-5d", count_from_libpax.pax); + dp_printf("%-5d", count.pax); } switch (DisplayPage) { @@ -264,32 +261,22 @@ void dp_drawPage(bool nextpage) { #if ((WIFICOUNTER) && (BLECOUNTER)) if (cfg.wifiscan) - dp_printf("WIFI:%-5d", count_from_libpax.wifi_count); + dp_printf("WIFI:%-5d", count.wifi_count); else dp_printf("WIFI:off"); if (cfg.blescan) -#if (COUNT_ENS) - if (cfg.enscount) - dp_printf(" CWA:%-5d", cwa_report()); - else -#endif - dp_printf("BLTH:%-5d", count_from_libpax.ble_count); + dp_printf("BLTH:%-5d", count.ble_count); else dp_printf(" BLTH:off"); #elif ((WIFICOUNTER) && (!BLECOUNTER)) if (cfg.wifiscan) - dp_printf("WIFI:%-5d", count_from_libpax.wifi_count); + dp_printf("WIFI:%-5d", count.wifi_count); else dp_printf("WIFI:off"); #elif ((!WIFICOUNTER) && (BLECOUNTER)) if (cfg.blescan) - dp_printf("BLTH:%-5d", count_from_libpax.ble_count); -#if (COUNT_ENS) - if (cfg.enscount) - dp_printf("(CWA:%d)", cwa_report()); - else -#endif - dp_printf("BLTH:off"); + dp_printf("BLTH:%-5d", count.ble_count); + dp_printf("BLTH:off"); #else dp_printf("Sniffer disabled"); #endif @@ -327,7 +314,6 @@ void dp_drawPage(bool nextpage) { #if (TIME_SYNC_INTERVAL) timeState = TimePulseTick ? ' ' : timeSetSymbols[timeSource]; - TimePulseTick = false; time(&now); localtime_r(&now, &timeinfo); strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); @@ -355,6 +341,8 @@ void dp_drawPage(bool nextpage) { dp_printf("%-4s", getSfName(updr2rps(LMIC.datarate))); dp_setFont(MY_FONT_SMALL, 0); #endif // HAS_LORA + + dp_dump(displaybuf); break; // ---------- page 1: lorawan parameters ---------- @@ -380,6 +368,8 @@ void dp_drawPage(bool nextpage) { LMIC.seqnoDn ? LMIC.seqnoDn - 1 : 0); dp_println(); dp_printf("SNR:%-5d RSSI:%-5d", (LMIC.snr + 2) / 4, LMIC.rssi); + + dp_dump(displaybuf); break; #else // flip page if we are unattended DisplayPage++; @@ -412,6 +402,8 @@ void dp_drawPage(bool nextpage) { dp_printf("No fix"); wasnofix = true; } + + dp_dump(displaybuf); break; #else // flip page if we are unattended DisplayPage++; @@ -435,10 +427,12 @@ void dp_drawPage(bool nextpage) { #ifdef HAS_BME680 // line 6-7: IAQ dp_printf("IAQ:%-3.0f", bme_status.iaq); -#else // is BME280 or BMP180 +#else // is BME280 or BMP180 // line 6-7: Pre dp_printf("PRE:%-2.1f", bme_status.pressure); -#endif // HAS_BME680 +#endif // HAS_BME680 + + dp_dump(displaybuf); break; // page 3 #else // flip page if we are unattended DisplayPage++; @@ -453,14 +447,15 @@ void dp_drawPage(bool nextpage) { localtime_r(&now, &timeinfo); strftime(strftime_buf, sizeof(strftime_buf), "%T", &timeinfo); dp_printf("%.8s", strftime_buf); + + dp_dump(displaybuf); break; // ---------- page 5: pax graph ---------- case 5: - dp_setFont(MY_FONT_NORMAL); - dp_setTextCursor(0, 0); - dp_printf("Pax graph"); + // update histogram + dp_plotCurve(count.pax, false); dp_dump(plotbuf); break; diff --git a/src/gpsread.cpp b/src/gpsread.cpp index 428604e4..3f1e0acd 100644 --- a/src/gpsread.cpp +++ b/src/gpsread.cpp @@ -6,68 +6,147 @@ // Local logging tag static const char TAG[] = __FILE__; -// we use NMEA ZDA sentence field 1 for time synchronization -// ZDA gives time for preceding pps pulse -// downsight is that it does not have a constant offset -// thus precision is only +/- 1 second - TinyGPSPlus gps; -TinyGPSCustom gpstime(gps, "GPZDA", 1); // field 1 = UTC time (hhmmss.ss) -TinyGPSCustom gpsday(gps, "GPZDA", 2); // field 2 = day (01..31) -TinyGPSCustom gpsmonth(gps, "GPZDA", 3); // field 3 = month (01..12) -TinyGPSCustom gpsyear(gps, "GPZDA", 4); // field 4 = year (4-digit) -static const String ZDA_Request = "$EIGPQ,ZDA*39\r\n"; TaskHandle_t GpsTask; - -#ifdef GPS_SERIAL HardwareSerial GPS_Serial(1); // use UART #1 -static uint16_t nmea_txDelay_ms = - (tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL) / portTICK_PERIOD_MS); -#else -static uint16_t nmea_txDelay_ms = 0; -#endif + +// Ublox UBX packet data + +// UBX CFG-PRT packet +byte CFG_PRT[] = { + 0xB5, // sync char 1 + 0x62, // sync char 2 + 0x06, // class + 0x00, // id + 0x14, // length + 0x00, // . + 0x01, // portID (UART 1) + 0x00, // reserved + 0x00, // txReady + 0x00, // . + 0b11010000, // UART mode: 8N1 + 0b00001000, // . + 0x00, // . + 0x00, // . + (byte)GPS_BAUDRATE, // baudrate + (byte)(GPS_BAUDRATE >> 8), // . + (byte)(GPS_BAUDRATE >> 16), // . + (byte)(GPS_BAUDRATE >> 24), // . + 0b00000011, // input protocols: NMEA + UBX + 0b00000000, // . + 0b00000010, // output protocols: NMEA + 0x00000000, // . + 0x00, // reserved + 0x00, // . + 0x00, // . + 0x00 // . +}; + +// Array of two bytes for CFG-MSG packets payload. +byte CFG_MSG_CID[][2] = {{0xF0, 0x01}, {0xF0, 0x02}, {0xF0, 0x03}, {0xF0, 0x05}, + {0xF0, 0x06}, {0xF0, 0x07}, {0xF0, 0x08}, {0xF0, 0x09}, + {0xF0, 0x0A}, {0xF0, 0x0E}, {0xF1, 0x00}, {0xF1, 0x03}, + {0xF1, 0x04}, {0xF1, 0x05}, {0xF1, 0x06}}; + +// UBX CFG-MSG packet +byte CFG_MSG[] = { + 0xB5, // sync char 1 + 0x62, // sync char 2 + 0x06, // class + 0x01, // id + 0x03, // length + 0x00, // . + 0x00, // payload (first byte from messages array element) + 0x00, // payload (second byte from messages array element) + 0x00 // payload (zero to disable message) +}; + +// UBX CFG-CFG packet +byte CFG_CFG[] = { + 0xB5, // sync char 1 + 0x62, // sync char 2 + 0x06, // class + 0x09, // id + 0x0D, // length + 0x00, // . + 0b00011111, // clearmask + 0b00000110, // . + 0x00, // . + 0x00, // . + 0x00, // savemask + 0x00, // . + 0x00, // . + 0x00, // . + 0b00011111, // loadmask + 0b00000110, // . + 0x00, // . + 0x00, // . + 0b00010001 // devicemask +}; + +// helper functions to send UBX commands to ublox gps chip + +void sendPacket(byte *packet, byte len) { + + uint8_t CK_A = 0; + uint8_t CK_B = 0; + + for (int i = 0; i < len; i++) + GPS_Serial.write(packet[i]); + + // calculate and send Fletcher checksum + for (int i = 2; i < len; i++) { + CK_A += packet[i]; + CK_B += CK_A; + } + GPS_Serial.write(CK_A); + GPS_Serial.write(CK_B); +} + +void restoreDefaults() { sendPacket(CFG_CFG, sizeof(CFG_CFG)); } +void changeBaudrate() { sendPacket(CFG_PRT, sizeof(CFG_PRT)); } + +void disableNmea() { + + // tinygps++ processes only $GPGGA/$GNGGA and $GPRMC/$GNRMC + // thus, we disable all other NMEA messages + + byte packetSize = sizeof(CFG_MSG); + + // Offset to the place where payload starts. + byte payloadOffset = 6; + + // Iterate over the messages array. + for (byte i = 0; i < sizeof(CFG_MSG_CID) / sizeof(*CFG_MSG_CID); i++) { + // Copy two bytes of payload to the packet buffer. + for (byte j = 0; j < sizeof(*CFG_MSG_CID); j++) { + CFG_MSG[payloadOffset + j] = CFG_MSG_CID[i][j]; + } + sendPacket(CFG_MSG, packetSize); + } +} // initialize and configure GPS int gps_init(void) { - if (!gps_config()) { - ESP_LOGE(TAG, "GPS chip initializiation error"); - return 0; - } - -#ifdef GPS_SERIAL ESP_LOGI(TAG, "Opening serial GPS"); + GPS_Serial.begin(GPS_SERIAL); -#elif defined GPS_I2C - ESP_LOGI(TAG, "Opening I2C GPS"); - Wire.begin(GPS_I2C, 400000); // I2C connect to GPS device with 400 KHz - Wire.beginTransmission(GPS_ADDR); - Wire.write(0x00); // dummy write - if (Wire.endTransmission()) { - ESP_LOGE(TAG, "Quectel L76 GPS chip not found"); - return 0; - } else - ESP_LOGI(TAG, "Quectel L76 GPS chip found"); -#endif + + restoreDefaults(); + delay(100); + + changeBaudrate(); + delay(100); + GPS_Serial.flush(); + GPS_Serial.updateBaudRate(GPS_BAUDRATE); + + disableNmea(); return 1; + } // gps_init() -// detect gps chipset type and configure it with device specific settings -int gps_config() { - int rslt = 1; // success -#if defined GPS_SERIAL - - /* insert user configuration here, if needed */ - -#elif defined GPS_I2C - - /* insert user configuration here, if needed */ - -#endif - return rslt; -} - // store current GPS location data in struct void gps_storelocation(gpsStatus_t *gps_store) { if (gps.location.isUpdated() && gps.location.isValid() && @@ -90,46 +169,45 @@ bool gps_hasfix() { } // function to poll UTC time from GPS NMEA data; note: this is costly -time_t get_gpstime(uint16_t *msec) { +time_t get_gpstime(uint16_t *msec = 0) { - // poll NMEA ZDA sentence -#ifdef GPS_SERIAL - GPS_Serial.print(ZDA_Request); - // wait for gps NMEA answer - // vTaskDelay(tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL)); -#elif defined GPS_I2C - Wire.print(ZDA_Request); -#endif + const uint16_t txDelay = + 70U * 1000 / (GPS_BAUDRATE / 9); // serial tx of 70 NMEA chars // did we get a current date & time? - if (gpstime.isValid()) { + if (gps.time.age() < 1000) { - uint32_t delay_ms = - gpstime.age() + nmea_txDelay_ms + NMEA_COMPENSATION_FACTOR; - uint32_t zdatime = atof(gpstime.value()); - - // convert UTC time from gps NMEA ZDA sentence to tm format + // convert tinygps time format to struct tm format struct tm gps_tm = {0}; - gps_tm.tm_sec = zdatime % 100; // second (UTC) - gps_tm.tm_min = (zdatime / 100) % 100; // minute (UTC) - gps_tm.tm_hour = zdatime / 10000; // hour (UTC) - gps_tm.tm_mday = atoi(gpsday.value()); // day, 01 to 31 - gps_tm.tm_mon = atoi(gpsmonth.value()) - 1; // month, 01 to 12 - gps_tm.tm_year = atoi(gpsyear.value()) - 1900; // year, YYYY - + gps_tm.tm_sec = gps.time.second(); + gps_tm.tm_min = gps.time.minute(); + gps_tm.tm_hour = gps.time.hour(); + gps_tm.tm_mday = gps.date.day(); + gps_tm.tm_mon = gps.date.month() - 1; // 1-12 -> 0-11 + gps_tm.tm_year = gps.date.year() - 1900; // 2000+ -> years since 1900 + // convert UTC tm to time_t epoch - gps_tm.tm_isdst = 0; // UTC has no DST + gps_tm.tm_isdst = 0; // UTC has no DST time_t t = mkgmtime(&gps_tm); - // add protocol delay with millisecond precision - t += (time_t)(delay_ms / 1000); - *msec = delay_ms % 1000; // fractional seconds +#ifdef GPS_INT + // if we have a recent GPS PPS pulse, sync on top of next second + uint16_t ppsDiff = millis() - lastPPS; + if (ppsDiff < 1000) + *msec = ppsDiff; + else { + ESP_LOGD(TAG, "no PPS from GPS"); + return 0; + } +#else + // best guess for sync on top of next second + *msec = gps.time.centisecond() * 10U + txDelay; +#endif return t; } ESP_LOGD(TAG, "no valid GPS time"); - return 0; } // get_gpstime() @@ -139,42 +217,17 @@ void gps_loop(void *pvParameters) { _ASSERT((uint32_t)pvParameters == 1); // FreeRTOS check + // feed GPS decoder with serial NMEA data from GPS device while (1) { + while (cfg.payloadmask & GPS_DATA) { - if (cfg.payloadmask & GPS_DATA) { -#ifdef GPS_SERIAL - // feed GPS decoder with serial NMEA data from GPS device - while (GPS_Serial.available()) { + while (GPS_Serial.available()) gps.encode(GPS_Serial.read()); - yield(); - } -#elif defined GPS_I2C - Wire.requestFrom(GPS_ADDR, 32); // caution: this is a blocking call - while (Wire.available()) { - gps.encode(Wire.read()); - delay(2); // 2ms delay according L76 datasheet - yield(); - } -#endif - // (only) while device time is not set or unsynched, and we have a valid - // GPS time, we trigger a device time update to poll time from GPS - if ((timeSource == _unsynced || timeSource == _set) && - (gpstime.isUpdated() && gpstime.isValid() && gpstime.age() < 1000)) { - calibrateTime(); - } - - } // if - - // show NMEA data in verbose mode, useful only for debugging GPS, very - // noisy ESP_LOGV(TAG, "GPS NMEA data: passed %u / failed: %u / with fix: - // %u", - // gps.passedChecksum(), gps.failedChecksum(), - // gps.sentencesWithFix()); - - yield(); // yield to CPU - - } // end of infinite loop + delay(5); + } + delay(1000); + } // infinite while loop } // gps_loop() diff --git a/src/hal/heltec.h b/src/hal/heltec.h index 47877577..55f7332a 100644 --- a/src/hal/heltec.h +++ b/src/hal/heltec.h @@ -18,7 +18,7 @@ #define CFG_sx1276_radio 1 #define HAS_DISPLAY 1 // OLED-Display on board -#define HAS_LED LED_BUILTIN // white LED on board +#define HAS_LED LED_BUILTIN // white LED on board (set to NOT_A_PIN to disable) #define HAS_BUTTON KEY_BUILTIN // button "PROG" on board // Pins for I2C interface of OLED Display diff --git a/src/hal/heltecv2.h b/src/hal/heltecv2.h index b33863ff..b6aab088 100644 --- a/src/hal/heltecv2.h +++ b/src/hal/heltecv2.h @@ -20,7 +20,7 @@ #define CFG_sx1276_radio 1 #define HAS_DISPLAY 1 // OLED-Display on board -#define HAS_LED LED_BUILTIN // white LED on board +#define HAS_LED LED_BUILTIN // white LED on board (set to NOT_A_PIN to disable) #define HAS_BUTTON KEY_BUILTIN // button "PROG" on board #define BAT_MEASURE_ADC ADC2_GPIO13_CHANNEL // battery probe GPIO pin diff --git a/src/hal/heltecv21.h b/src/hal/heltecv21.h index 9586edfd..a24d875a 100644 --- a/src/hal/heltecv21.h +++ b/src/hal/heltecv21.h @@ -20,7 +20,7 @@ #define CFG_sx1276_radio 1 #define HAS_DISPLAY 1 // OLED-Display on board -#define HAS_LED LED_BUILTIN // white LED on board +#define HAS_LED LED_BUILTIN // white LED on board (set to NOT_A_PIN to disable) #define HAS_BUTTON KEY_BUILTIN // button "PROG" on board #define BAT_MEASURE_ADC ADC1_GPIO37_CHANNEL // battery probe GPIO pin diff --git a/src/hal/lolin32lite.h b/src/hal/lolin32lite.h index 1c860393..3f9f9fe0 100644 --- a/src/hal/lolin32lite.h +++ b/src/hal/lolin32lite.h @@ -10,7 +10,7 @@ // Hardware related definitions for lolin32lite (without LoRa shield) #define HAS_LED LED_BUILTIN // on board LED on GPIO5 -#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW +#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW (set to NOT_A_PIN to disable) #define MY_SDA SDA #define MY_SCL SCL diff --git a/src/hal/lolin32litelora.h b/src/hal/lolin32litelora.h index f0b99250..d3ae2133 100644 --- a/src/hal/lolin32litelora.h +++ b/src/hal/lolin32litelora.h @@ -15,7 +15,7 @@ #define HAS_DISPLAY 1 // OLED-Display on board //#define MY_DISPLAY_FLIP 1 // uncomment this for rotated display -#define HAS_LED 22 // ESP32 GPIO12 (pin22) On Board LED +#define HAS_LED 22 // ESP32 GPIO12 (pin22) On Board LED (set to NOT_A_PIN to disable) #define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW #define HAS_RGB_LED SmartLed rgb_led(LED_WS2812, 1, GPIO_NUM_13) // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED #define HAS_BUTTON 15 // ESP32 GPIO15 (pin15) Button is on the LoraNode32 shield diff --git a/src/hal/lopy.h b/src/hal/lopy.h index 733eb603..e196ee1a 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -20,11 +20,6 @@ #define HAS_ANTENNA_SWITCH (16) // pin for switching wifi antenna #define WIFI_ANTENNA 0 // 0 = internal, 1 = external -// uncomment this only if your LoPy runs on a PYTRACK BOARD -#define HAS_GPS 1 -#define GPS_I2C GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) -#define GPS_ADDR 0x10 - // uncomment this only if your LoPy runs on a EXPANSION BOARD //#define HAS_LED (12) // use if LoPy is on Expansion Board, this has a user LED //#define LED_ACTIVE_LOW 1 // use if LoPy is on Expansion Board, this has a user LED diff --git a/src/hal/lopy4.h b/src/hal/lopy4.h index fd99a7d7..0c5999f0 100644 --- a/src/hal/lopy4.h +++ b/src/hal/lopy4.h @@ -30,11 +30,6 @@ #define HAS_ANTENNA_SWITCH (21) // pin for switching wifi antenna (P12) #define WIFI_ANTENNA 0 // 0 = internal, 1 = external -// uncomment defines in this section ONLY if your LoPy lives on a PYTRACK BOARD -//#define HAS_GPS 1 -//#define GPS_I2C GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) -//#define GPS_ADDR 0x10 - // uncomment defines in this section ONLY if your LoPy lives on a EXPANSION BOARD //#define HAS_LED (12) // use if LoPy is on Expansion Board, this has a user LED //#define LED_ACTIVE_LOW 1 // use if LoPy is on Expansion Board, this has a user LED diff --git a/src/hal/ttgov1.h b/src/hal/ttgov1.h index bb1b63e7..cc0493c8 100644 --- a/src/hal/ttgov1.h +++ b/src/hal/ttgov1.h @@ -14,7 +14,7 @@ #define HAS_DISPLAY 1 // OLED-Display on board //#define MY_DISPLAY_FLIP 1 // uncomment this for rotated display -#define HAS_LED LED_BUILTIN +#define HAS_LED LED_BUILTIN // set to NOT_A_PIN to disable #define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW #define HAS_BUTTON KEY_BUILTIN diff --git a/src/hal/ttgov21new.h b/src/hal/ttgov21new.h index 71c22bca..fbaae22b 100644 --- a/src/hal/ttgov21new.h +++ b/src/hal/ttgov21new.h @@ -16,10 +16,12 @@ #define CFG_sx1276_radio 1 // HPD13A LoRa SoC // enable only if you want to store a local paxcount table on the device -#define HAS_SDCARD 2 // // this board has a SDMMC card-reader/writer +#define HAS_SDCARD 2 // this board has a SDMMC card-reader/writer #define HAS_DISPLAY 1 #define HAS_LED (25) // green on board LED +//#define HAS_LED NOT_A_PIN + #define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7 #define BAT_VOLTAGE_DIVIDER 2 // voltage divider 100k/100k on board diff --git a/src/if482.cpp b/src/if482.cpp index 37c12c38..81add69a 100644 --- a/src/if482.cpp +++ b/src/if482.cpp @@ -86,18 +86,19 @@ static const char TAG[] = __FILE__; String IF482_Frame(time_t t) { - char mon, out[IF482_FRAME_SIZE + 1]; + char mon, out[IF482_FRAME_SIZE + 1], buf[IF482_FRAME_SIZE - 3]; if (sntp_get_sync_status() == SNTP_SYNC_STATUS_IN_PROGRESS) mon = 'M'; // time had been set but sync not completed else mon = 'A'; // time has been set and was recently synced - // generate IF482 telegram - // snprintf(out, sizeof(out), "O%cL%s\r", mon, myTZ.dateTime(t, UTC_TIME, - // "ymdwHis").c_str()); - - // ESP_LOGD(TAG, "[%s] IF482 date/time: %s", ctime(time(NULL), out); + // generate IF482 telegram for local time + struct tm tt; + localtime_r(&t, &tt); + mktime(&tt); + strftime(buf, sizeof(buf), "%y%m%d%u%H%M%S", &tt); + snprintf(out, sizeof(out), "O%cL%s\r", mon, buf); return out; } diff --git a/src/led.cpp b/src/led.cpp index b0b302d6..8095a3a9 100644 --- a/src/led.cpp +++ b/src/led.cpp @@ -212,7 +212,7 @@ void ledLoop(void *parameter) { previousLEDState = LEDState; } // give yield to CPU - delay(2); + delay(5); } // while(1) }; // ledloop() diff --git a/src/ledmatrixdisplay.cpp b/src/ledmatrixdisplay.cpp index e6b1d070..8940d6ec 100644 --- a/src/ledmatrixdisplay.cpp +++ b/src/ledmatrixdisplay.cpp @@ -13,6 +13,7 @@ uint8_t MatrixDisplayIsOn = 0; static uint8_t displaybuf[LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT / 8] = {0}; static unsigned long ulLastNumMacs = 0; static time_t ulLastTime = time(NULL); +static struct count_payload_t count; // libpax count storage hw_timer_t *matrixDisplayIRQ = NULL; @@ -76,12 +77,12 @@ void refreshTheMatrixDisplay(bool nextPage) { case 0: // update counter values from libpax - libpax_counter_count(&count_from_libpax); + libpax_counter_count(&count); if (cfg.countermode == 1) { // cumulative counter mode -> display total number of pax - if (ulLastNumMacs != count_from_libpax.pax) { - ulLastNumMacs = count_from_libpax.pax; + if (ulLastNumMacs != count.pax) { + ulLastNumMacs = count.pax; matrix.clear(); DrawNumber(String(ulLastNumMacs)); } @@ -89,10 +90,10 @@ void refreshTheMatrixDisplay(bool nextPage) { else { // cyclic counter mode -> plot a line diagram - if (ulLastNumMacs != count_from_libpax.pax) { + if (ulLastNumMacs != count.pax) { // next count cycle? - if (count_from_libpax.pax == 0) { + if (count.pax == 0) { // matrix full? then scroll left 1 dot, else increment column if (col < (LED_MATRIX_WIDTH - 1)) @@ -104,7 +105,7 @@ void refreshTheMatrixDisplay(bool nextPage) { matrix.drawPoint(col, row, 0); // clear current dot // scale and set new dot - ulLastNumMacs = count_from_libpax.pax; + ulLastNumMacs = count.pax; level = ulLastNumMacs / LINE_DIAGRAM_DIVIDER; row = level <= LED_MATRIX_HEIGHT ? LED_MATRIX_HEIGHT - 1 - level % LED_MATRIX_HEIGHT @@ -120,7 +121,7 @@ void refreshTheMatrixDisplay(bool nextPage) { if (ulLastTime != t) { ulLastTime = t; matrix.clear(); - //DrawNumber(myTZ.dateTime("H:i:s").c_str()); + // DrawNumber(myTZ.dateTime("H:i:s").c_str()); } break; diff --git a/src/libpax_helpers.cpp b/src/libpax_helpers.cpp index 9883648c..937dfd04 100644 --- a/src/libpax_helpers.cpp +++ b/src/libpax_helpers.cpp @@ -5,18 +5,9 @@ static const char TAG[] = __FILE__; // libpax payload struct count_payload_t count_from_libpax; -uint16_t volatile libpax_macs_ble, libpax_macs_wifi; - -void process_count(void) { - ESP_LOGD(TAG, "pax: %d / %d / %d", count_from_libpax.pax, - count_from_libpax.wifi_count, count_from_libpax.ble_count); - libpax_macs_ble = count_from_libpax.ble_count; - libpax_macs_wifi = count_from_libpax.wifi_count; - setSendIRQ(); -} void init_libpax(void) { - libpax_counter_init(process_count, &count_from_libpax, cfg.sendcycle * 2, + libpax_counter_init(setSendIRQ, &count_from_libpax, cfg.sendcycle * 2, cfg.countermode); libpax_counter_start(); } \ No newline at end of file diff --git a/src/lorawan-devices-repo/vendor/opensource/esp32-paxcounter-packed.js b/src/lorawan-devices-repo/vendor/opensource/esp32-paxcounter-packed.js index d82e56e9..b9fc15a1 100644 --- a/src/lorawan-devices-repo/vendor/opensource/esp32-paxcounter-packed.js +++ b/src/lorawan-devices-repo/vendor/opensource/esp32-paxcounter-packed.js @@ -90,12 +90,7 @@ function decodeUplink(input) { data = decode(input.bytes, [uint32, uint8], ['time', 'timestatus']); } } - - if (input.fPort === 10) { - // ENS count - data = decode(input.bytes, [uint16], ['ens']); - } - + data.bytes = input.bytes; // comment out if you do not want to include the original payload data.port = input.fPort; // comment out if you do not want to inlude the port diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 32f7f1f7..299481fc 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -179,10 +179,10 @@ void showLoraKeys(void) { // all EUI buffer so we do it here to a temp // buffer to be able to display them uint8_t buf[32]; - os_getDevEui((u1_t *)buf); - printKey("DevEUI", buf, 8, true); os_getArtEui((u1_t *)buf); printKey("AppEUI", buf, 8, true); + os_getDevEui((u1_t *)buf); + printKey("DevEUI", buf, 8, true); os_getDevKey((u1_t *)buf); printKey("AppKey", buf, 16, false); } @@ -314,7 +314,7 @@ esp_err_t lmic_init(void) { "lorasendtask", // name of task 3072, // stack size of task (void *)1, // parameter of the task - 1, // priority of the task + 2, // priority of the task &lorasendTask, // task handle 1); // CPU core diff --git a/src/main.cpp b/src/main.cpp index fda59d8e..2e20fb76 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,62 +25,54 @@ licenses. Refer to LICENSE.txt file in repository for more details. // Tasks and timers: -Task Core Prio Purpose +Task Core Prio Purpose ------------------------------------------------------------------------------- -ledloop 0 3 blinks LEDs -spiloop 0 2 reads/writes data on spi interface -IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer +ledloop* 1 1 blinks LEDs +spiloop# 0 2 reads/writes data on spi interface +lmictask* 1 2 MCCI LMiC LORAWAN stack +clockloop# 1 6 generates realtime telegrams for external clock +mqttloop# 1 5 reads/writes data on ETH interface +timesync_proc# 1 7 processes realtime time sync requests +irqhandler# 1 4 application IRQ (i.e. displayrefresh) +gpsloop* 1 1 reads data from GPS via serial or i2c +lorasendtask# 1 2 feeds data from lora sendqueue to lmcic +rmcd_process# 1 1 Remote command interpreter loop -lmictask 1 2 MCCI LMiC LORAWAN stack -clockloop 1 4 generates realtime telegrams for external clock -mqttloop 1 2 reads/writes data on ETH interface -timesync_proc 1 3 processes realtime time sync requests -irqhandler 1 2 cyclic tasks (i.e. displayrefresh) triggered by timers -gpsloop 1 1 reads data from GPS via serial or i2c -lorasendtask 1 1 feeds data from lora sendqueue to lmcic -rmcd_process 1 1 Remote command interpreter loop -IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator +* spinning task, always ready +# blocked/waiting task Low priority numbers denote low priority tasks. - -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. +------------------------------------------------------------------------------- // ESP32 hardware timers ------------------------------------------------------------------------------- 0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS) 1 ppsIRQ -> pps clock irq -> 1sec +2 (unused) 3 MatrixDisplayIRQ -> matrix mux cycle -> 0,5ms (MATRIX_DISPLAY_SCAN_US) -// Interrupt routines -------------------------------------------------------------------------------- - -irqHandlerTask (Core 1), see irqhandler.cpp - -fired by hardware -DisplayIRQ -> esp32 timer 0 -CLOCKIRQ -> esp32 timer 1 or external GPIO (RTC_INT or GPS_INT) -MatrixDisplayIRQ-> esp32 timer 3 -ButtonIRQ -> external GPIO -PMUIRQ -> PMU chip GPIO - -fired by software -TIMESYNC_IRQ -> setTimeSyncIRQ() -> Ticker.h -CYCLIC_IRQ -> setCyclicIRQ() -> Ticker.h -SENDCYCLE_IRQ -> setSendIRQ() -> xTimer -BME_IRQ -> setBMEIRQ() -> Ticker.h - -ClockTask (Core 1), see timekeeper.cpp - -fired by hardware -CLOCKIRQ -> esp32 timer 1 - - // External RTC timer (if present) ------------------------------------------------------------------------------- triggers pps 1 sec impulse + +// Interrupt routines +------------------------------------------------------------------------------- + +ISRs fired by CPU or GPIO: +DisplayIRQ <- esp32 timer 0 +CLOCKIRQ <- esp32 timer 1 or GPIO (RTC_INT) +MatrixDisplayIRQ<- esp32 timer 3 +ButtonIRQ <- GPIO <- Button +PMUIRQ <- GPIO <- PMU chip + +Application IRQs fired by software: +TIMESYNC_IRQ <- setTimeSyncIRQ() <- Ticker.h +CYCLIC_IRQ <- setCyclicIRQ() <- Ticker.h +SENDCYCLE_IRQ <- setSendIRQ() <- xTimer or libpax callback +BME_IRQ <- setBMEIRQ() <- Ticker.h + */ // Basic Config @@ -126,7 +118,7 @@ void setup() { snprintf(clientId, 20, "paxcounter_%08x", hashedmac); ESP_LOGI(TAG, "Starting %s v%s (runmode=%d / restarts=%d)", clientId, PROGVERSION, RTC_runmode, RTC_restarts); - ESP_LOGI(TAG, "code build date: %d", _COMPILETIME); + ESP_LOGI(TAG, "code build date: %d", compileTime()); // print chip information on startup if in verbose mode after coldstart #if (VERBOSE) @@ -244,9 +236,9 @@ void setup() { "ledloop", // name of task 1024, // stack size of task (void *)1, // parameter of the task - 3, // priority of the task + 1, // priority of the task &ledLoopTask, // task handle - 0); // CPU core + 1); // CPU core #endif // initialize wifi antenna @@ -328,7 +320,7 @@ void setup() { ESP_LOGI(TAG, "Starting GPS Feed..."); xTaskCreatePinnedToCore(gps_loop, // task function "gpsloop", // name of task - 4096, // stack size of task + 8192, // stack size of task (void *)1, // parameter of the task 1, // priority of the task &GpsTask, // task handle @@ -339,15 +331,9 @@ void setup() { // initialize sensors #if (HAS_SENSORS) #if (HAS_SENSOR_1) -#if (COUNT_ENS) - ESP_LOGI(TAG, "init CWA-counter"); - if (cwa_init()) - strcat_P(features, " CWA"); -#else strcat_P(features, " SENS(1)"); sensor_init(); #endif -#endif #if (HAS_SENSOR_2) strcat_P(features, " SENS(2)"); sensor_init(); @@ -432,7 +418,7 @@ void setup() { "irqhandler", // name of task 4096, // stack size of task (void *)1, // parameter of the task - 2, // priority of the task + 4, // priority of the task &irqHandlerTask, // task handle 1); // CPU core @@ -494,8 +480,7 @@ void setup() { cyclicTimer.attach(HOMECYCLE, setCyclicIRQ); // only if we have a timesource we do timesync -#if ((TIME_SYNC_LORAWAN) || (TIME_SYNC_LORASERVER) || (HAS_GPS) || \ - defined HAS_RTC) +#if ((TIME_SYNC_LORAWAN) || (TIME_SYNC_LORASERVER) || (HAS_GPS) || (HAS_RTC)) #if (defined HAS_IF482 || defined HAS_DCF77) ESP_LOGI(TAG, "Starting Clock Controller..."); @@ -507,8 +492,7 @@ void setup() { #endif ESP_LOGI(TAG, "Starting Timekeeper..."); - _ASSERT(timepulse_init()); // setup pps timepulse - timepulse_start(); // starts pps and cyclic time sync + _ASSERT(timepulse_init()); // starts pps and cyclic time sync strcat_P(features, " TIME"); #endif // timesync diff --git a/src/mqttclient.cpp b/src/mqttclient.cpp index d7ddb4bf..c8d85ceb 100644 --- a/src/mqttclient.cpp +++ b/src/mqttclient.cpp @@ -37,7 +37,7 @@ esp_err_t mqtt_init(void) { SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE); ESP_LOGI(TAG, "Starting MQTTloop..."); - xTaskCreatePinnedToCore(mqtt_client_task, "mqttloop", 4096, (void *)NULL, 1, + xTaskCreatePinnedToCore(mqtt_client_task, "mqttloop", 4096, (void *)NULL, 5, &mqttTask, 1); return ESP_OK; } diff --git a/src/paxcounter_orig.conf b/src/paxcounter_orig.conf index 0fe927b9..e0f0eb11 100644 --- a/src/paxcounter_orig.conf +++ b/src/paxcounter_orig.conf @@ -18,6 +18,11 @@ #define PAYLOAD_ENCODER 2 // payload encoder: 1=Plain, 2=Packed, 3=Cayenne LPP dynamic, 4=Cayenne LPP packed #define COUNTERMODE 0 // 0=cyclic, 1=cumulative, 2=cyclic confirmed +// default settings for transmission of sensor data (first list = data on / second line = data off) +#define PAYLOADMASK \ + ((GPS_DATA | MEMS_DATA | COUNT_DATA | SENSOR1_DATA | SENSOR2_DATA | SENSOR3_DATA) & \ + (~BATT_DATA) & (~RESERVED_DATA)) + // MAC sniffing parameters #define BLECOUNTER 1 // set to 0 if you do not want to install the BLE sniffer #define WIFICOUNTER 1 // set to 0 if you do not want to install the WIFI sniffer @@ -27,10 +32,6 @@ #define BLESCANWINDOW 80 // [milliseconds] scan window, see below, 3 .. 10240, default 80ms #define BLESCANINTERVAL 80 // [illiseconds] scan interval, see below, 3 .. 10240, default 80ms = 100% duty cycle -// Corona Exposure Notification Service(ENS) counter -#define COUNT_ENS 0 // count found number of devices which advertise Exposure Notification Service - // set to 1 if you want to enable this function [default=0] - /* Note: guide for setting bluetooth parameters * * |< Scan Window > |< Scan Window > | ... |< Scan Window > | diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 08c7618d..71c6f453 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -1,7 +1,6 @@ // Basic Config #include "globals.h" #include "rcommand.h" -#include "libpax_helpers.h" // Local logging tag static const char TAG[] = __FILE__; @@ -397,15 +396,6 @@ void set_flush(uint8_t val[]) { // used to open receive window on LoRaWAN class a nodes }; -void set_enscount(uint8_t val[]) { - ESP_LOGI(TAG, "Remote command: set ENS_COUNT to %s", val[0] ? "on" : "off"); - cfg.enscount = val[0] ? 1 : 0; - if (val[0]) - cfg.payloadmask |= (uint8_t)SENSOR1_DATA; - else - cfg.payloadmask &= (uint8_t)~SENSOR1_DATA; -} - void set_loadconfig(uint8_t val[]) { ESP_LOGI(TAG, "Remote command: load config from NVRAM"); loadConfig(); @@ -430,7 +420,7 @@ static const cmd_t table[] = { {0x10, set_rgblum, 1}, {0x13, set_sensor, 2}, {0x14, set_payloadmask, 1}, {0x15, set_bme, 1}, {0x16, set_batt, 1}, {0x17, set_wifiscan, 1}, - {0x18, set_enscount, 1}, {0x19, set_sleepcycle, 2}, + {0x18, set_flush, 0}, {0x19, set_sleepcycle, 2}, {0x20, set_loadconfig, 0}, {0x21, set_saveconfig, 0}, {0x80, get_config, 0}, {0x81, get_status, 0}, {0x83, get_batt, 0}, {0x84, get_gps, 0}, @@ -493,7 +483,7 @@ void rcmd_process(void *pvParameters) { rcmd_execute(RcmdBuffer.cmd, RcmdBuffer.cmdLen); } - delay(2); // yield to CPU + delay(5); // yield to CPU } // rcmd_process() // enqueue remote command diff --git a/src/reset.cpp b/src/reset.cpp index d21a042d..b67d8dae 100644 --- a/src/reset.cpp +++ b/src/reset.cpp @@ -126,6 +126,11 @@ void enter_deepsleep(const uint64_t wakeup_sec, gpio_num_t wakeup_gpio) { sds011_sleep(); #endif +// flush & close sd card, if we have +#if (HAS_SDCARD) + sdcard_close(); +#endif + // wait a while (max 100 sec) to clear send queues ESP_LOGI(TAG, "Waiting until send queues are empty..."); for (i = 100; i > 0; i--) { diff --git a/src/rtctime.cpp b/src/rtctime.cpp index cb87c9de..eb25698d 100644 --- a/src/rtctime.cpp +++ b/src/rtctime.cpp @@ -25,14 +25,14 @@ uint8_t rtc_init(void) { } #if (TIME_SYNC_COMPILEDATE) - // initialize a blank RTC without battery backup with compiled time + // initialize a blank RTC without battery backup with build time RtcDateTime tt = Rtc.GetDateTime(); time_t t = tt.Epoch32Time(); // sec2000 -> epoch if (!Rtc.IsDateTimeValid() || !timeIsValid(t)) { - ESP_LOGW(TAG, "RTC has no recent time, setting to compiled time"); - Rtc.SetDateTime( - RtcDateTime(_COMPILETIME - SECS_YR_2000)); // epoch -> sec2000 + ESP_LOGW(TAG, "RTC has no recent time, setting to compiletime"); + Rtc.SetDateTime(RtcDateTime(mkgmtime(compileTime()) - + SECS_YR_2000)); // epoch -> sec2000 } #endif @@ -62,15 +62,23 @@ uint8_t set_rtctime(time_t t) { // t is sec epoch time } } // set_rtctime() -time_t get_rtctime(void) { +time_t get_rtctime(uint16_t *msec) { time_t t = 0; + *msec = 0; if (I2C_MUTEX_LOCK()) { if (Rtc.IsDateTimeValid() && Rtc.GetIsRunning()) { RtcDateTime tt = Rtc.GetDateTime(); t = tt.Epoch32Time(); // sec2000 -> epoch } I2C_MUTEX_UNLOCK(); - return timeIsValid(t); +#ifdef RTC_INT + // adjust time to top of next second by waiting TimePulseTick to flip + bool lastTick = TimePulseTick; + while (TimePulseTick == lastTick) { + }; + t++; +#endif + return t; } else { ESP_LOGE(TAG, "RTC get time failure"); return 0; // failure diff --git a/src/sdcard.cpp b/src/sdcard.cpp index 925ab207..c8696bb1 100644 --- a/src/sdcard.cpp +++ b/src/sdcard.cpp @@ -1,4 +1,7 @@ // routines for writing data to an SD-card, if present +// use FAT32 formatted card +// check whether your card reader supports SPI oder SDMMC and select appropriate +// SD low level driver in board hal file // Local logging tag static const char TAG[] = __FILE__; @@ -8,20 +11,26 @@ static const char TAG[] = __FILE__; #ifdef HAS_SDCARD static bool useSDCard; - -static void createFile(void); +static void openFile(void); File fileSDCard; -bool sdcard_init() { - ESP_LOGI(TAG, "looking for SD-card..."); +#if HAS_SDCARD == 1 +SPIClass sd_spi; +#endif + +bool sdcard_init(bool create) { // for usage of SD drivers on ESP32 platform see // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sdspi_host.html // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sdmmc_host.html + ESP_LOGI(TAG, "looking for SD-card..."); #if HAS_SDCARD == 1 // use SD SPI host driver - useSDCard = SD.begin(SDCARD_CS, SDCARD_MOSI, SDCARD_MISO, SDCARD_SCLK); + digitalWrite(SDCARD_CS, HIGH); + sd_spi.begin(SDCARD_SCLK, SDCARD_MISO, SDCARD_MOSI, SDCARD_CS); + digitalWrite(SDCARD_CS, LOW); + useSDCard = SD.begin(SDCARD_CS, sd_spi); #elif HAS_SDCARD == 2 // use SD MMC host driver // enable internal pullups of sd-data lines gpio_set_pull_mode(gpio_num_t(SDCARD_DATA0), GPIO_PULLUP_ONLY); @@ -33,20 +42,27 @@ bool sdcard_init() { if (useSDCard) { ESP_LOGI(TAG, "SD-card found"); - createFile(); - } else + openFile(); + return true; + } else { ESP_LOGI(TAG, "SD-card not found"); - return useSDCard; + return false; + } +} + +void sdcard_close(void) { + ESP_LOGI(TAG, "closing SD-card"); + fileSDCard.flush(); + fileSDCard.close(); } void sdcardWriteData(uint16_t noWifi, uint16_t noBle, - __attribute__((unused)) uint16_t noBleCWA) { + __attribute__((unused)) uint16_t voltage) { static int counterWrites = 0; - char tempBuffer[12 + 1]; + char tempBuffer[20 + 1]; time_t t = time(NULL); struct tm tt; - localtime_r(&t, &tt); - mktime(&tt); + gmtime_r(&t, &tt); // make UTC timestamp #if (HAS_SDS011) sdsStatus_t sds; @@ -55,71 +71,85 @@ void sdcardWriteData(uint16_t noWifi, uint16_t noBle, if (!useSDCard) return; - ESP_LOGD(TAG, "writing to SD-card"); - strftime(tempBuffer, sizeof(tempBuffer), "%d.%m.%Y", &tt); + ESP_LOGI(TAG, "SD: writing data"); + strftime(tempBuffer, sizeof(tempBuffer), "%FT%TZ", &tt); fileSDCard.print(tempBuffer); - strftime(tempBuffer, sizeof(tempBuffer), "%H.%M.%S", &tt); + snprintf(tempBuffer, sizeof(tempBuffer), ",%d,%d", noWifi, noBle); fileSDCard.print(tempBuffer); - sprintf(tempBuffer, "%d,%d", noWifi, noBle); - fileSDCard.print(tempBuffer); -#if (COUNT_ENS) - sprintf(tempBuffer, ",%d", noBleCWA); +#if (defined BAT_MEASURE_ADC || defined HAS_PMU) + snprintf(tempBuffer, sizeof(tempBuffer), ",%d", voltage); fileSDCard.print(tempBuffer); #endif #if (HAS_SDS011) sds011_store(&sds); - sprintf(tempBuffer, ",%5.1f,%4.1f", sds.pm10, sds.pm25); + snprintf(tempBuffer, sizeof(tempBuffer), ",%5.1f,%4.1f", sds.pm10 / 10, + sds.pm25 / 10); fileSDCard.print(tempBuffer); #endif fileSDCard.println(); if (++counterWrites > 2) { // force writing to SD-card - ESP_LOGD(TAG, "flushing data to card"); + ESP_LOGI(TAG, "SD: flushing data"); fileSDCard.flush(); counterWrites = 0; } } -void createFile(void) { - char bufferFilename[8 + 1 + 3 + 1]; +void openFile(void) { + char bufferFilename[30]; useSDCard = false; - for (int i = 0; i < 100; i++) { - sprintf(bufferFilename, SDCARD_FILE_NAME, i); - // ESP_LOGD(TAG, "SD: looking for file <%s>", bufferFilename); + snprintf(bufferFilename, sizeof(bufferFilename), "/%s.csv", SDCARD_FILE_NAME); + ESP_LOGI(TAG, "SD: looking for file <%s>", bufferFilename); #if HAS_SDCARD == 1 - bool fileExists = SD.exists(bufferFilename); + bool fileExists = SD.exists(bufferFilename); #elif HAS_SDCARD == 2 - bool fileExists = SD_MMC.exists(bufferFilename); + bool fileExists = SD_MMC.exists(bufferFilename); #endif - if (!fileExists) { - // ESP_LOGD(TAG, "SD: file does not exist: opening"); + // file not exists, create it + if (!fileExists) { + ESP_LOGD(TAG, "SD: file not found, creating..."); #if HAS_SDCARD == 1 - fileSDCard = SD.open(bufferFilename, FILE_WRITE); + fileSDCard = SD.open(bufferFilename, FILE_WRITE); #elif HAS_SDCARD == 2 - fileSDCard = SD_MMC.open(bufferFilename, FILE_WRITE); + fileSDCard = SD_MMC.open(bufferFilename, FILE_WRITE); #endif - if (fileSDCard) { - ESP_LOGD(TAG, "SD: name opened: <%s>", bufferFilename); - fileSDCard.print(SDCARD_FILE_HEADER); -#if (COUNT_ENS) - fileSDCard.print(SDCARD_FILE_HEADER_CWA); // for Corona-data (CWA) + if (fileSDCard) { + ESP_LOGD(TAG, "SD: name opened: <%s>", bufferFilename); + fileSDCard.print(SDCARD_FILE_HEADER); +#if (defined BAT_MEASURE_ADC || defined HAS_PMU) + fileSDCard.print(SDCARD_FILE_HEADER_VOLTAGE); // for battery level data #endif #if (HAS_SDS011) - fileSDCard.print(SDCARD_FILE_HEADER_SDS011); + fileSDCard.print(SDCARD_FILE_HEADER_SDS011); #endif - fileSDCard.println(); - useSDCard = true; - break; - } + fileSDCard.println(); + useSDCard = true; } } + + // file exists, append data + else { + ESP_LOGD(TAG, "SD: file found, opening..."); + +#if HAS_SDCARD == 1 + fileSDCard = SD.open(bufferFilename, FILE_APPEND); +#elif HAS_SDCARD == 2 + fileSDCard = SD_MMC.open(bufferFilename, FILE_APPEND); +#endif + + if (fileSDCard) { + ESP_LOGD(TAG, "SD: name opened: <%s>", bufferFilename); + useSDCard = true; + } + } + return; } diff --git a/src/sds011read.cpp b/src/sds011read.cpp index a693f651..b1f4d4b0 100644 --- a/src/sds011read.cpp +++ b/src/sds011read.cpp @@ -10,35 +10,37 @@ static const char TAG[] = __FILE__; #if (HAS_IF482) #error cannot use IF482 together with SDS011 (both use UART#2) #endif -// UART(2) is unused in this project -static HardwareSerial sdsSerial(2); // so we use it here -static SDS011 sdsSensor; // fine dust sensor -// the results of the sensor: -static float pm10, pm25; -boolean isSDS011Active; +SdsDustSensor sds(Serial2); + +bool isSDS011Active = false; +static float pm10 = 0.0, pm25 = 0.0; // init bool sds011_init() { - pm25 = pm10 = 0.0; - sdsSensor.begin(&sdsSerial, SDS_RX, SDS_TX); - sds011_sleep(); // we do sleep/wakup by ourselves + sds.begin(9600, SERIAL_8N1, SDS_RX, SDS_TX); + sds011_wakeup(); + ESP_LOGI(TAG, "SDS011: %s", sds.queryFirmwareVersion().toString().c_str()); + sds.setQueryReportingMode(); + return true; } // reading data: void sds011_loop() { if (isSDS011Active) { - int sdsErrorCode = sdsSensor.read(&pm25, &pm10); - if (sdsErrorCode) { - pm25 = pm10 = 0.0; - ESP_LOGI(TAG, "SDS011 error: %d", sdsErrorCode); + PmResult pm = sds.queryPm(); + if (!pm.isOk()) { + ESP_LOGE(TAG, "SDS011: query error %s", pm.statusToString().c_str()); + pm10 = pm25 = 0.0; } else { - ESP_LOGI(TAG, "fine-dust-values: %5.1f,%4.1f", pm10, pm25); + ESP_LOGI(TAG, "SDS011: %s", pm.toString().c_str()); + pm10 = pm.pm10; + pm25 = pm.pm25; } + ESP_LOGD(TAG, "SDS011: go to sleep"); sds011_sleep(); } - return; } // retrieving stored data: @@ -49,17 +51,16 @@ void sds011_store(sdsStatus_t *sds_store) { // putting the SDS-sensor to sleep void sds011_sleep(void) { - sdsSensor.sleep(); - isSDS011Active = false; + WorkingStateResult state = sds.sleep(); + isSDS011Active = state.isWorking(); } // start the SDS-sensor // needs 30 seconds for warming up void sds011_wakeup() { - if (!isSDS011Active) { - sdsSensor.wakeup(); - isSDS011Active = true; - } + WorkingStateResult state = sds.wakeup(); + isSDS011Active = state.isWorking(); + ESP_LOGD(TAG, "SDS011: %s", state.toString().c_str()); } #endif // HAS_SDS011 diff --git a/src/senddata.cpp b/src/senddata.cpp index 5a310761..fedee7da 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -5,6 +5,8 @@ void setSendIRQ(TimerHandle_t xTimer) { xTaskNotify(irqHandlerTask, SENDCYCLE_IRQ, eSetBits); } +void setSendIRQ(void) { setSendIRQ(NULL); } + void initSendDataTimer(uint8_t sendcycle) { static TimerHandle_t SendDataTimer = NULL; @@ -65,31 +67,26 @@ void SendPayload(uint8_t port) { mqtt_enqueuedata(&SendBuffer); #endif -// write data to sdcard, if present -#if (HAS_SDCARD) - if (port == COUNTERPORT) { - sdcardWriteData(libpax_macs_wifi, libpax_macs_ble -#if (COUNT_ENS) - , - cwa_report() -#endif - ); - } -#endif - } // SendPayload -// interrupt triggered function to prepare payload to send +// timer triggered function to prepare payload to send void sendData() { uint8_t bitmask = cfg.payloadmask; uint8_t mask = 1; + #if (HAS_GPS) gpsStatus_t gps_status; #endif #if (HAS_SDS011) sdsStatus_t sds_status; #endif +#if ((WIFICOUNTER) || (BLECOUNTER)) + struct count_payload_t count = + count_from_libpax; // copy values from global libpax var + ESP_LOGD(TAG, "Sending count results: pax=%d / wifi=%d / ble=%d", count.pax, + count.wifi_count, count.ble_count); +#endif while (bitmask) { switch (bitmask & mask) { @@ -97,14 +94,14 @@ void sendData() { #if ((WIFICOUNTER) || (BLECOUNTER)) case COUNT_DATA: payload.reset(); + #if !(PAYLOAD_OPENSENSEBOX) - ESP_LOGI(TAG, "Sending libpax wifi count: %d", libpax_macs_wifi); - payload.addCount(libpax_macs_wifi, MAC_SNIFF_WIFI); + payload.addCount(count.wifi_count, MAC_SNIFF_WIFI); if (cfg.blescan) { - ESP_LOGI(TAG, "Sending libpax ble count: %d", libpax_macs_ble); - payload.addCount(libpax_macs_ble, MAC_SNIFF_BLE); + payload.addCount(count.ble_count, MAC_SNIFF_BLE); } #endif + #if (HAS_GPS) if (GPSPORT == COUNTERPORT) { // send GPS position only if we have a fix @@ -115,23 +112,35 @@ void sendData() { ESP_LOGD(TAG, "No valid GPS position"); } #endif + #if (PAYLOAD_OPENSENSEBOX) - ESP_LOGI(TAG, "Sending libpax wifi count: %d", libpax_macs_wifi); - payload.addCount(libpax_macs_wifi, MAC_SNIFF_WIFI); + payload.addCount(count.wifi_count, MAC_SNIFF_WIFI); if (cfg.blescan) { - ESP_LOGI(TAG, "Sending libpax ble count: %d", libpax_macs_ble); - payload.addCount(libpax_macs_ble, MAC_SNIFF_BLE); + payload.addCount(count.ble_count, MAC_SNIFF_BLE); #endif + #if (HAS_SDS011) sds011_store(&sds_status); payload.addSDS(sds_status); #endif - SendPayload(COUNTERPORT); + #ifdef HAS_DISPLAY - dp_plotCurve(libpax_macs_ble + libpax_macs_wifi, true); + dp_plotCurve(count.pax, true); #endif - break; + +#if (HAS_SDCARD) + sdcardWriteData(count.wifi_count, count.ble_count +#if (defined BAT_MEASURE_ADC || defined HAS_PMU) + , + read_voltage() #endif + ); +#endif // HAS_SDCARD + + SendPayload(COUNTERPORT); + break; // case COUNTDATA + +#endif // ((WIFICOUNTER) || (BLECOUNTER)) #if (HAS_BME) case MEMS_DATA: @@ -162,10 +171,6 @@ void sendData() { payload.reset(); payload.addSensor(sensor_read(1)); SendPayload(SENSOR1PORT); -#if (COUNT_ENS) - if (cfg.countermode != 1) - cwa_clear(); -#endif break; #endif #if (HAS_SENSOR_2) diff --git a/src/sensor.cpp b/src/sensor.cpp index 21f212f5..2d077175 100644 --- a/src/sensor.cpp +++ b/src/sensor.cpp @@ -2,12 +2,6 @@ #include "globals.h" #include "sensor.h" -#if (COUNT_ENS) -#include "payload.h" -#include "corona.h" -extern PayloadConvert payload; -#endif - // Local logging tag static const char TAG[] = __FILE__; @@ -53,16 +47,10 @@ uint8_t *sensor_read(uint8_t sensor) { case 1: // insert user specific sensor data frames here - // note: Sensor1 fields are used for ENS count, if ENS detection enabled -#if (COUNT_ENS) - if (cfg.enscount) - payload.addCount(cwa_report(), MAC_SNIFF_BLE_ENS); -#else buf[0] = length; buf[1] = 0x01; buf[2] = 0x02; buf[3] = 0x03; -#endif break; case 2: diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 876bff85..6a4d2904 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -19,9 +19,9 @@ static const char TAG[] = __FILE__; // G = GPS / R = RTC / L = LORA / * = no sync / ? = never synced const char timeSetSymbols[] = {'G', 'R', 'L', '*', '?'}; -bool volatile TimePulseTick = false; +DRAM_ATTR bool TimePulseTick = false; +DRAM_ATTR unsigned long lastPPS = millis(); timesource_t timeSource = _unsynced; -time_t _COMPILETIME = compileTime(__DATE__); TaskHandle_t ClockTask = NULL; hw_timer_t *ppsIRQ = NULL; @@ -40,8 +40,7 @@ Ticker timesyncer; void setTimeSyncIRQ() { xTaskNotify(irqHandlerTask, TIMESYNC_IRQ, eSetBits); } void calibrateTime(void) { - ESP_LOGD(TAG, "[%0.3f] calibrateTime, timeSource == %d", _seconds(), - timeSource); + time_t t = 0; uint16_t t_msec = 0; @@ -57,7 +56,7 @@ void calibrateTime(void) { // has RTC -> fallback to RTC time #ifdef HAS_RTC - t = get_rtctime(); + t = get_rtctime(&t_msec); // set time from RTC - method will check if time is valid setMyTime((uint32_t)t, t_msec, _rtc); #endif @@ -101,26 +100,27 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, vTaskDelay(pdMS_TO_TICKS(1000 - t_msec % 1000)); } + // from here on we are on top of next second + tv.tv_sec = time_to_set; tv.tv_usec = 0; sntp_sync_time(&tv); ESP_LOGI(TAG, "[%0.3f] UTC time: %d.000 sec", _seconds(), time_to_set); - // if we have a software pps timer, shift it to top of second - if (ppsIRQ != NULL) { - - timerWrite(ppsIRQ, 0); // reset pps timer - CLOCKIRQ(); // fire clock pps, this advances time 1 sec - } - -// if we have got an external timesource, set RTC time and shift RTC_INT pulse -// to top of second + // if we have a precise time timesource, set RTC time and shift RTC_INT + // pulse to top of second #ifdef HAS_RTC if ((mytimesource == _gps) || (mytimesource == _lora)) set_rtctime(time_to_set); #endif + // if we have a software pps timer, shift it to top of second + if (ppsIRQ != NULL) { + timerWrite(ppsIRQ, 0); // reset pps timer + CLOCKIRQ(); // fire clock pps to advance wall clock by 1 sec + } + timeSource = mytimesource; // set global variable timesyncer.attach(TIME_SYNC_INTERVAL * 60, setTimeSyncIRQ); @@ -132,7 +132,7 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, "[%0.3f] Failed to synchronise time from source %c | unix sec " "obtained from source: %d | unix sec at program compilation: %d", _seconds(), timeSetSymbols[mytimesource], time_to_set, - _COMPILETIME); + compileTime()); } } @@ -140,29 +140,26 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, uint8_t timepulse_init() { // set esp-idf API sntp sync mode - //sntp_init(); + // sntp_init(); sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED); -// use time pulse from GPS as time base with fixed 1Hz frequency +// if we have, use PPS time pulse from GPS for syncing time on top of second #ifdef GPS_INT - - // setup external interupt pin for rising edge GPS INT + // setup external interupt pin for rising edge of GPS PPS pinMode(GPS_INT, INPUT_PULLDOWN); - // setup external rtc 1Hz clock as pulse per second clock - ESP_LOGI(TAG, "Timepulse: external (GPS)"); - return 1; // success + attachInterrupt(digitalPinToInterrupt(GPS_INT), GPSIRQ, RISING); +#endif -// use pulse from on board RTC chip as time base with fixed frequency -#elif defined RTC_INT +// if we have, use pulse from on board RTC chip as time base for calendar time +#if defined RTC_INT - // setup external interupt pin for falling edge RTC INT - pinMode(RTC_INT, INPUT_PULLUP); - - // setup external rtc 1Hz clock as pulse per second clock + // setup external rtc 1Hz clock pulse if (I2C_MUTEX_LOCK()) { Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz); Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock); I2C_MUTEX_UNLOCK(); + pinMode(RTC_INT, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING); ESP_LOGI(TAG, "Timepulse: external (RTC)"); return 1; // success } else { @@ -172,33 +169,39 @@ uint8_t timepulse_init() { return 1; // success #else - // use ESP32 hardware timer as time base with adjustable frequency + // use ESP32 hardware timer as time base for calendar time ppsIRQ = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec timerAlarmWrite(ppsIRQ, 10000, true); // 1000ms + timerAttachInterrupt(ppsIRQ, &CLOCKIRQ, true); + timerAlarmEnable(ppsIRQ); ESP_LOGI(TAG, "Timepulse: internal (ESP32 hardware timer)"); return 1; // success #endif -} // timepulse_init -void timepulse_start(void) { -#ifdef GPS_INT // start external clock gps pps line - attachInterrupt(digitalPinToInterrupt(GPS_INT), CLOCKIRQ, RISING); -#elif defined RTC_INT // start external clock rtc - attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING); -#else // start internal clock esp32 hardware timer - timerAttachInterrupt(ppsIRQ, &CLOCKIRQ, true); - timerAlarmEnable(ppsIRQ); -#endif + // start cyclic time sync + timesyncer.attach(TIME_SYNC_INTERVAL * 60, setTimeSyncIRQ); // get time if we don't have one if (timeSource != _set) setTimeSyncIRQ(); // init systime by RTC or GPS or LORA - // start cyclic time sync - timesyncer.attach(TIME_SYNC_INTERVAL * 60, setTimeSyncIRQ); + +} // timepulse_init + +// interrupt service routine triggered by GPS PPS +void IRAM_ATTR GPSIRQ(void) { + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + // take timestamp + lastPPS = millis(); // last time of pps + + // yield only if we should + if (xHigherPriorityTaskWoken) + portYIELD_FROM_ISR(); } -// interrupt service routine triggered by either pps or esp32 hardware timer +// interrupt service routine triggered by esp32 hardware timer void IRAM_ATTR CLOCKIRQ(void) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; @@ -211,9 +214,7 @@ void IRAM_ATTR CLOCKIRQ(void) { // flip time pulse ticker, if needed #ifdef HAS_DISPLAY -#if (defined GPS_INT || defined RTC_INT) - TimePulseTick = !TimePulseTick; // flip pulse ticker -#endif + TimePulseTick = !TimePulseTick; // flip global variable pulse ticker #endif // yield only if we should @@ -224,7 +225,9 @@ void IRAM_ATTR CLOCKIRQ(void) { // helper function to check plausibility of a given epoch time bool timeIsValid(time_t const t) { // is t a time in the past? we use compile time to guess - return (t > _COMPILETIME); + // compile time is some local time, but we do not know it's time zone + // thus, we go 1 full day back to be sure to catch a time in the past + return (t > (compileTime() - 86400)); } // helper function to calculate serial transmit time @@ -252,7 +255,7 @@ void clock_init(void) { "clockloop", // name of task 3072, // stack size of task (void *)1, // task parameter - 4, // priority of the task + 6, // priority of the task &ClockTask, // task handle 1); // CPU core @@ -283,7 +286,7 @@ void clock_loop(void *taskparameter) { // ClockTask // set calendar time for next second of clock output tt = (time_t)(current_time + 1); localtime_r(&tt, &t); - mktime(&t); + tt = mktime(&t); #if defined HAS_IF482 @@ -293,13 +296,13 @@ void clock_loop(void *taskparameter) { // ClockTask if (xTaskNotifyWait(0x00, ULONG_MAX, ¤t_time, txDelay) == pdTRUE) { tt = (time_t)(current_time + 1); localtime_r(&tt, &t); - mktime(&t); + tt = mktime(&t); } // send IF482 telegram - IF482.print(IF482_Frame(t)); // note: telegram is for *next* second + IF482.print(IF482_Frame(tt)); // note: telegram is for *next* second - ESP_LOGD(TAG, "[%0.3f] IF482: %s", _seconds(), IF482_Frame(t)); + ESP_LOGD(TAG, "[%0.3f] IF482: %s", _seconds(), IF482_Frame(tt).c_str()); #elif defined HAS_DCF77 @@ -340,7 +343,7 @@ void clock_loop(void *taskparameter) { // ClockTask } // clock_loop() // we use compile date to create a time_t reference "in the past" -time_t compileTime(const String compile_date) { +time_t compileTime(void) { char s_month[5]; int year; @@ -353,10 +356,11 @@ time_t compileTime(const String compile_date) { if (secs == -1) { // determine date - // we go one day back to bypass unknown timezone of local time - sscanf(compile_date.c_str(), "%s %d %d", s_month, &t.tm_mday - 1, &year); + sscanf(__DATE__, "%s %d %d", s_month, &t.tm_mday, &year); t.tm_mon = (strstr(month_names, s_month) - month_names) / 3; t.tm_year = year - 1900; + // determine time + sscanf(__TIME__, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); // convert to secs local time secs = mktime(&t); diff --git a/src/timesync.cpp b/src/timesync.cpp index aa969897..9b2c5f99 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -34,7 +34,7 @@ void timesync_init(void) { "timesync_proc", // name of task 4096, // stack size of task (void *)1, // task parameter - 3, // priority of the task + 7, // priority of the task &timeSyncProcTask, // task handle 1); // CPU core }