Merge branch 'development' into master
This commit is contained in:
25 files changed
+553
-88
No files matched your search
@@ -1,5 +1,3 @@
|
||||
#ifdef BLECOUNTER
|
||||
|
||||
/* code snippets taken from
|
||||
https://github.com/nkolban/esp32-snippets/tree/master/BLE/scanner
|
||||
*/
|
||||
@@ -235,8 +233,6 @@ esp_err_t register_ble_callback(void) {
|
||||
|
||||
} // register_ble_callback
|
||||
|
||||
#endif // BLECOUNTER
|
||||
|
||||
void start_BLEscan(void) {
|
||||
#ifdef BLECOUNTER
|
||||
ESP_LOGI(TAG, "Initializing bluetooth scanner ...");
|
||||
|
||||
+20
-22
@@ -32,8 +32,7 @@ int bme_init(void) {
|
||||
// return = 0 -> error / return = 1 -> success
|
||||
|
||||
// block i2c bus access
|
||||
if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) ==
|
||||
pdTRUE) {
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
|
||||
Wire.begin(HAS_BME);
|
||||
iaqSensor.begin(BME_ADDR, Wire);
|
||||
@@ -62,17 +61,16 @@ int bme_init(void) {
|
||||
ESP_LOGE(TAG, "BSEC subscription error");
|
||||
goto error;
|
||||
}
|
||||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "I2c bus busy - BME680 initialization error");
|
||||
goto error;
|
||||
}
|
||||
|
||||
xSemaphoreGive(I2Caccess); // release i2c bus access
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
return 1;
|
||||
|
||||
error:
|
||||
xSemaphoreGive(I2Caccess); // release i2c bus access
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
return 0;
|
||||
|
||||
} // bme_init()
|
||||
@@ -106,24 +104,24 @@ void bme_loop(void *pvParameters) {
|
||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||
|
||||
#ifdef HAS_BME
|
||||
// block i2c bus access
|
||||
while (xSemaphoreTake(I2Caccess, portMAX_DELAY) == pdTRUE) {
|
||||
|
||||
if (iaqSensor.run()) { // If new data is available
|
||||
bme_status.raw_temperature = iaqSensor.rawTemperature;
|
||||
bme_status.raw_humidity = iaqSensor.rawHumidity;
|
||||
bme_status.temperature = iaqSensor.temperature;
|
||||
bme_status.humidity = iaqSensor.humidity;
|
||||
bme_status.pressure =
|
||||
(iaqSensor.pressure / 100.0); // conversion Pa -> hPa
|
||||
bme_status.iaq = iaqSensor.iaqEstimate;
|
||||
bme_status.iaq_accuracy = iaqSensor.iaqAccuracy;
|
||||
bme_status.gas = iaqSensor.gasResistance;
|
||||
updateState();
|
||||
while (1) {
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
if (iaqSensor.run()) { // If new data is available
|
||||
bme_status.raw_temperature = iaqSensor.rawTemperature;
|
||||
bme_status.raw_humidity = iaqSensor.rawHumidity;
|
||||
bme_status.temperature = iaqSensor.temperature;
|
||||
bme_status.humidity = iaqSensor.humidity;
|
||||
bme_status.pressure =
|
||||
(iaqSensor.pressure / 100.0); // conversion Pa -> hPa
|
||||
bme_status.iaq = iaqSensor.iaqEstimate;
|
||||
bme_status.iaq_accuracy = iaqSensor.iaqAccuracy;
|
||||
bme_status.gas = iaqSensor.gasResistance;
|
||||
updateState();
|
||||
}
|
||||
I2C_MUTEX_UNLOCK();
|
||||
}
|
||||
xSemaphoreGive(I2Caccess); // release i2c bus access
|
||||
|
||||
} // while
|
||||
}
|
||||
#endif
|
||||
ESP_LOGE(TAG, "BME task ended");
|
||||
vTaskDelete(BmeTask); // should never be reached
|
||||
|
||||
+13
-8
@@ -123,25 +123,30 @@ void reset_counters() {
|
||||
void do_timesync() {
|
||||
#ifdef TIME_SYNC_INTERVAL
|
||||
|
||||
// sync time & date by GPS if we have valid gps time
|
||||
// set system time to time source GPS, if we have valid gps time
|
||||
#ifdef HAS_GPS
|
||||
if (gps.time.isValid()) {
|
||||
setTime(gps.time.hour(), gps.time.minute(), gps.time.second(),
|
||||
gps.date.day(), gps.date.month(), gps.date.year());
|
||||
ESP_LOGI(TAG, "Time synced by GPS to %02d:%02d:%02d", hour(), minute(),
|
||||
second());
|
||||
// set RTC time to time source GPS, if RTC is present
|
||||
#ifdef HAS_RTC
|
||||
if (!set_rtctime(RtcDateTime(now())))
|
||||
ESP_LOGE(TAG, "RTC set time failure");
|
||||
#endif
|
||||
time_t tt = myTZ.toLocal(now());
|
||||
ESP_LOGI(TAG, "GPS has set system time to %02d/%02d/%d %02d:%02d:%02d",
|
||||
month(tt), day(tt), year(tt), hour(tt), minute(tt), second(tt));
|
||||
return;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "No valid GPS time");
|
||||
}
|
||||
#endif // HAS_GPS
|
||||
|
||||
// sync time by LoRa Network if network supports DevTimeReq
|
||||
#ifdef LMIC_ENABLE_DeviceTimeReq
|
||||
// Schedule a network time request at the next possible time
|
||||
// set system time to time source LoRa Network, if network supports DevTimeReq
|
||||
#elif defined LMIC_ENABLE_DeviceTimeReq
|
||||
// Schedule a network time sync request at the next possible time
|
||||
LMIC_requestNetworkTime(user_request_network_time_callback, &userUTCTime);
|
||||
ESP_LOGI(TAG, "Network time request scheduled");
|
||||
#endif
|
||||
#endif // HAS_GPS
|
||||
|
||||
#endif // TIME_SYNC_INTERVAL
|
||||
} // do_timesync()
|
||||
|
||||
+53
-16
@@ -1,5 +1,27 @@
|
||||
#ifdef HAS_DISPLAY
|
||||
|
||||
/*
|
||||
|
||||
Display-Mask (128 x 64 pixel):
|
||||
|
||||
| 111111
|
||||
|0123456789012345
|
||||
------------------
|
||||
0|PAX:aabbccddee
|
||||
1|PAX:aabbccddee
|
||||
2|B:a.bcV Sats:ab
|
||||
3|BLTH:abcde SF:ab
|
||||
4|WIFI:abcde ch:ab
|
||||
5|RLIM:abcd abcdKB
|
||||
6|xxxxxxxxxxxxxxxx
|
||||
6|20:27:00* 27.Feb
|
||||
7|yyyyyyyyyyyyyyab
|
||||
|
||||
line 6: x = Text for LORA status OR time/date
|
||||
line 7: y = Text for LMIC status; ab = payload queue
|
||||
|
||||
*/
|
||||
|
||||
// Basic Config
|
||||
#include "globals.h"
|
||||
#include <esp_spi_flash.h> // needed for reading ESP32 chip attributes
|
||||
@@ -19,6 +41,10 @@ const char lora_datarate[] = {"1211100908078CNA1211109C8C7C"};
|
||||
const char lora_datarate[] = {"121110090807FSNA"};
|
||||
#endif
|
||||
|
||||
// helper arry for converting month values to text
|
||||
char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
uint8_t volatile DisplayState = 0;
|
||||
|
||||
// helper function, prints a hex key on display
|
||||
@@ -99,8 +125,7 @@ void init_display(const char *Productname, const char *Version) {
|
||||
void refreshtheDisplay() {
|
||||
|
||||
// block i2c bus access
|
||||
if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) ==
|
||||
pdTRUE) {
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
|
||||
// set display on/off according to current device configuration
|
||||
if (DisplayState != cfg.screenon) {
|
||||
@@ -126,26 +151,29 @@ void refreshtheDisplay() {
|
||||
// update Battery status (line 2)
|
||||
#ifdef HAS_BATTERY_PROBE
|
||||
u8x8.setCursor(0, 2);
|
||||
u8x8.printf("B:%.1fV", batt_voltage / 1000.0);
|
||||
u8x8.printf("B:%.2fV", batt_voltage / 1000.0);
|
||||
#endif
|
||||
|
||||
// update GPS status (line 2)
|
||||
#ifdef HAS_GPS
|
||||
u8x8.setCursor(9, 2);
|
||||
if (!gps.location.isValid()) // if no fix then display Sats value inverse
|
||||
{
|
||||
u8x8.setInverseFont(1);
|
||||
u8x8.printf("Sats:%.2d", gps.satellites.value());
|
||||
u8x8.setInverseFont(0);
|
||||
} else
|
||||
u8x8.printf("Sats:%.2d", gps.satellites.value());
|
||||
// have we ever got valid gps data?
|
||||
if (gps.passedChecksum() > 0) {
|
||||
u8x8.setCursor(9, 2);
|
||||
if (!gps.location.isValid()) // if no fix then display Sats value inverse
|
||||
{
|
||||
u8x8.setInverseFont(1);
|
||||
u8x8.printf("Sats:%.2d", gps.satellites.value());
|
||||
u8x8.setInverseFont(0);
|
||||
} else
|
||||
u8x8.printf("Sats:%.2d", gps.satellites.value());
|
||||
}
|
||||
#endif
|
||||
|
||||
// update bluetooth counter + LoRa SF (line 3)
|
||||
// update bluetooth counter + LoRa SF (line 3)
|
||||
#ifdef BLECOUNTER
|
||||
u8x8.setCursor(0, 3);
|
||||
if (cfg.blescan)
|
||||
u8x8.printf("BLTH:%-4d", macs_ble);
|
||||
u8x8.printf("BLTH:%-5d", macs_ble);
|
||||
else
|
||||
u8x8.printf("%s", "BLTH:off");
|
||||
#endif
|
||||
@@ -163,7 +191,7 @@ void refreshtheDisplay() {
|
||||
|
||||
// update wifi counter + channel display (line 4)
|
||||
u8x8.setCursor(0, 4);
|
||||
u8x8.printf("WIFI:%-4d", macs_wifi);
|
||||
u8x8.printf("WIFI:%-5d", macs_wifi);
|
||||
u8x8.setCursor(11, 4);
|
||||
u8x8.printf("ch:%02d", channel);
|
||||
|
||||
@@ -174,9 +202,18 @@ void refreshtheDisplay() {
|
||||
u8x8.printf("%4dKB", getFreeRAM() / 1024);
|
||||
|
||||
#ifdef HAS_LORA
|
||||
// update LoRa status display (line 6)
|
||||
|
||||
u8x8.setCursor(0, 6);
|
||||
#ifndef HAS_RTC
|
||||
// update LoRa status display (line 6)
|
||||
u8x8.printf("%-16s", display_line6);
|
||||
#else
|
||||
// update time/date display (line 6)
|
||||
time_t t = myTZ.toLocal(now());
|
||||
u8x8.printf("%02d:%02d:%02d%c %2d.%3s", hour(t), minute(t), second(t),
|
||||
timeStatus() == timeSet ? '*' : '?', day(t),
|
||||
printmonth[month(t)]);
|
||||
#endif
|
||||
|
||||
// update LMiC event display (line 7)
|
||||
u8x8.setCursor(0, 7);
|
||||
@@ -193,7 +230,7 @@ void refreshtheDisplay() {
|
||||
|
||||
#endif // HAS_LORA
|
||||
|
||||
xSemaphoreGive(I2Caccess); // release i2c bus access
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
}
|
||||
|
||||
} // refreshDisplay()
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ gpsStatus_t gps_status;
|
||||
TaskHandle_t GpsTask;
|
||||
|
||||
#ifdef GPS_SERIAL
|
||||
HardwareSerial GPS_Serial(1);
|
||||
HardwareSerial GPS_Serial(1); // use UART #1
|
||||
#endif
|
||||
|
||||
// initialize and configure GPS
|
||||
|
||||
+5
-1
@@ -6,6 +6,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Hardware related definitions for generic ESP32 boards
|
||||
// generic.h is kitchensink with all available options
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa or has no LoRa
|
||||
#define HAS_SPI 1 // comment out if device shall not send data via SPI
|
||||
@@ -30,7 +31,7 @@
|
||||
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
//#define DISPLAY_FLIP 1 // use if display is rotated
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||
|
||||
#define HAS_LED (21) // on board LED
|
||||
@@ -47,6 +48,9 @@
|
||||
#define MY_OLED_SCL (15)
|
||||
#define MY_OLED_RST (16)
|
||||
|
||||
// Pins for on board DS3231 RTC chip
|
||||
#define HAS_RTC MY_OLED_SDA, MY_OLED_SCL // SDA, SCL
|
||||
|
||||
// Pins for LORA chip SPI interface, reset line and interrupt lines
|
||||
#define LORA_SCK (5)
|
||||
#define LORA_CS (18)
|
||||
|
||||
+4
-4
@@ -24,13 +24,13 @@
|
||||
|
||||
// enable only if device has these sensors, otherwise comment these lines
|
||||
// BME680 sensor on I2C bus
|
||||
//#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
|
||||
//#define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
|
||||
//#define HAS_BME SDA, SCL
|
||||
//#define BME_ADDR BME680_I2C_ADDR_PRIMARY // !! connect SDIO of BME680 to GND !!
|
||||
|
||||
// display (if connected)
|
||||
//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
//#define MY_OLED_SDA (21)
|
||||
//#define MY_OLED_SCL (22)
|
||||
//#define MY_OLED_SDA SDA
|
||||
//#define MY_OLED_SCL SCL
|
||||
//#define MY_OLED_RST U8X8_PIN_NONE
|
||||
//#define DISPLAY_FLIP 1 // use if display is rotated
|
||||
|
||||
|
||||
+10
-3
@@ -9,9 +9,9 @@
|
||||
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
|
||||
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
#define HAS_LED NOT_A_PIN // green on board LED
|
||||
//#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
|
||||
#define HAS_LED NOT_A_PIN // green on board LED is useless, is GPIO25, which switches power for Lora+Display
|
||||
#define HAS_LOWPOWER_SWITCH GPIO_NUM_25 // switches power for LoRa chip + display (0 = off / 1 = on)
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL
|
||||
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||
#define HAS_BUTTON GPIO_NUM_36 // on board button (next to reset)
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
#define MY_OLED_SCL (22)
|
||||
#define MY_OLED_RST U8X8_PIN_NONE
|
||||
|
||||
// Pins for on board DS3231 RTC chip
|
||||
#define HAS_RTC MY_OLED_SDA, MY_OLED_SCL // SDA, SCL
|
||||
#define RTC_INT GPIO_NUM_34 // interrupt input from rtc
|
||||
|
||||
// Settings for IF482 interface
|
||||
//#define HAS_IF482 9600, SERIAL_7E1, GPIO_NUM_12, GPIO_NUM_14 // IF482 serial port parameters
|
||||
|
||||
// Pins for LORA chip SPI interface, reset line and interrupt lines
|
||||
#define LORA_SCK (5)
|
||||
#define LORA_CS (18)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
#define HAS_LED (25) // green on board LED
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||
|
||||
// Pins for I2C interface of OLED Display
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
//#define DISPLAY_FLIP 1 // rotated display
|
||||
//#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
|
||||
//#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
//#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||
|
||||
// Pins for I2C interface of OLED Display
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#if defined HAS_IF482 && defined HAS_RTC
|
||||
|
||||
/*
|
||||
|
||||
IF482 Generator to control clocks with IF482 telegram input (e.g. BÜRK BU190)
|
||||
|
||||
Example IF482 telegram: "OAL160806F170400"
|
||||
|
||||
IF482 Specification:
|
||||
http://www.mobatime.com/fileadmin/user_upload/downloads/TE-112023.pdf
|
||||
|
||||
The IF 482 telegram is a time telegram, which sends the time and date
|
||||
information as ASCII characters through the serial interface RS 232 or RS 422.
|
||||
|
||||
Communication parameters:
|
||||
|
||||
Baud rate: 9600 Bit/s
|
||||
Data bits 7
|
||||
Parity: even
|
||||
Stop bit: 1
|
||||
Jitter: < 50ms
|
||||
|
||||
Interface : RS232 or RS422
|
||||
|
||||
Synchronization: Telegram ends at the beginning of the second
|
||||
specified in the telegram
|
||||
|
||||
Cycle: 1 second
|
||||
|
||||
Format of ASCII telegram string:
|
||||
|
||||
Byte Meaning ASCII Hex
|
||||
1 Start of telegram O 4F
|
||||
2 Monitoring* A 41
|
||||
3 Time-Season** W/S/U/L 57 or 53
|
||||
4 Year tens 0 .. 9 30 .. 39
|
||||
5 Year unit 0 .. 9 30 .. 39
|
||||
6 Month tens 0 or 1 30 or 31
|
||||
7 Month unit 0 .. 9 30 .. 39
|
||||
8 Day tens 0 .. 3 30 .. 33
|
||||
9 Day unit 0 .. 9 30 .. 39
|
||||
10 Day of week*** 1 .. 7 31 .. 37
|
||||
11 Hours tens 0 .. 2 30 .. 32
|
||||
12 Hours unit 0 .. 9 30 .. 39
|
||||
13 Minutes tens 0 .. 5 30 .. 35
|
||||
14 Minutes unit 0 .. 9 30 .. 39
|
||||
15 Seconds tens 0 .. 5 30 .. 35
|
||||
16 Seconds unit 0 .. 9 30 .. 39
|
||||
17 End of telegram CR 0D
|
||||
|
||||
*) Monitoring:
|
||||
With a correctly received time in the sender unit, the ASCII character 'A' is
|
||||
issued. If 'M' is issued, this indicates that the sender was unable to receive
|
||||
any time signal for over 12 hours (time is accepted with ‘A’ and ‘M’).
|
||||
|
||||
**) Season:
|
||||
W: Standard time,
|
||||
S: Season time,
|
||||
U: UTC time (not supported by all systems),
|
||||
L: Local Time
|
||||
|
||||
***) Day of week:
|
||||
not evaluated by model BU-190
|
||||
|
||||
*/
|
||||
|
||||
#include "if482.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
TaskHandle_t IF482Task;
|
||||
|
||||
HardwareSerial IF482(2); // use UART #2 (note: #1 may be in use for serial GPS)
|
||||
|
||||
// initialize and configure GPS
|
||||
int if482_init(void) {
|
||||
|
||||
// open serial interface
|
||||
IF482.begin(HAS_IF482);
|
||||
|
||||
// use rtc 1Hz clock for triggering IF482 telegram send
|
||||
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
|
||||
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock);
|
||||
pinMode(RTC_INT, INPUT_PULLUP);
|
||||
|
||||
ESP_LOGI(TAG, "IF482 generator initialized");
|
||||
|
||||
return 1;
|
||||
|
||||
} // if482_init
|
||||
|
||||
String if482Telegram(time_t t) {
|
||||
|
||||
char mon;
|
||||
char buf[14] = "000000F000000";
|
||||
char out[17];
|
||||
|
||||
switch (timeStatus()) { // indicates if time has been set and recently synced
|
||||
case timeSet: // time is set and is synced
|
||||
mon = 'A';
|
||||
break;
|
||||
case timeNeedsSync: // time had been set but sync attempt did not succeed
|
||||
mon = 'M';
|
||||
break;
|
||||
default: // time not set, no valid time
|
||||
mon = '?';
|
||||
break;
|
||||
} // switch
|
||||
|
||||
if (!timeNotSet) // do we have valid time?
|
||||
snprintf(buf, sizeof buf, "%02u%02u%02u%1u%02u%02u%02u", year(t) - 2000,
|
||||
month(t), day(t), weekday(t), hour(t), minute(t), second(t));
|
||||
|
||||
snprintf(out, sizeof out, "O%cL%s\r", mon, buf);
|
||||
return out;
|
||||
}
|
||||
|
||||
void if482_loop(void *pvParameters) {
|
||||
|
||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||
|
||||
TickType_t wakeTime;
|
||||
time_t t, tt;
|
||||
const TickType_t shotTime = pdMS_TO_TICKS(IF482_OFFSET);
|
||||
|
||||
// wait until begin of a new second
|
||||
t = tt = now();
|
||||
do {
|
||||
tt = now();
|
||||
} while (t == tt);
|
||||
|
||||
const TickType_t startOffset = xTaskGetTickCount();
|
||||
|
||||
// task remains in blocked state until it is notified by isr
|
||||
for (;;) {
|
||||
xTaskNotifyWait(
|
||||
0x00, // don't clear any bits on entry
|
||||
ULONG_MAX, // clear all bits on exit
|
||||
&wakeTime, // receives moment of call from isr
|
||||
portMAX_DELAY); // wait forever (missing error handling here...)
|
||||
|
||||
t = myTZ.toLocal(now());
|
||||
wakeTime -= startOffset;
|
||||
|
||||
// now we're synced to start of second t and wait
|
||||
// until it's time to start transmit telegram for t+1
|
||||
vTaskDelayUntil(&wakeTime, shotTime);
|
||||
IF482.print(if482Telegram(t+1));
|
||||
}
|
||||
vTaskDelete(IF482Task); // shoud never be reached
|
||||
} // if482_loop()
|
||||
|
||||
// interrupt service routine triggered by RTC 1Hz precise clock
|
||||
void IRAM_ATTR IF482IRQ() {
|
||||
xTaskNotifyFromISR(IF482Task, xTaskGetTickCountFromISR(), eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
#endif // HAS_IF482
|
||||
+1
-1
@@ -61,7 +61,7 @@ void IRAM_ATTR SendCycleIRQ() {
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
void IRAM_ATTR DisplayIRQ() {
|
||||
xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, NULL);
|
||||
xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
#endif
|
||||
|
||||
+8
-2
@@ -455,6 +455,12 @@ void user_request_network_time_callback(void *pVoidUserUTCTime,
|
||||
|
||||
// Update system time with time read from the network
|
||||
setTime(*pUserUTCTime);
|
||||
ESP_LOGI(TAG, "Time synced by LoRa network to %02d:%02d:%02d", hour(),
|
||||
minute(), second());
|
||||
#ifdef HAS_RTC
|
||||
if (!set_rtctime(*pUserUTCTime))
|
||||
ESP_LOGE(TAG, "RTC set time failure");
|
||||
#endif
|
||||
time_t t = myTZ.toLocal(now());
|
||||
ESP_LOGI(TAG,
|
||||
"LORA Network has set system time to %02d/%02d/%d %02d:%02d:%02d",
|
||||
month(t), day(t), year(t), hour(t), minute(t), second(t));
|
||||
}
|
||||
+54
-14
@@ -29,6 +29,7 @@ Task Core Prio Purpose
|
||||
====================================================================================
|
||||
wifiloop 0 4 rotates wifi channels
|
||||
ledloop 0 3 blinks LEDs
|
||||
if482loop 1 3 serial feed of IF482 time telegrams
|
||||
spiloop 0 2 reads/writes data on spi interface
|
||||
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
|
||||
|
||||
@@ -44,11 +45,15 @@ Tasks using i2c bus all must have same priority, because using mutex semaphore
|
||||
(irqhandler, bmeloop)
|
||||
|
||||
ESP32 hardware timers
|
||||
==========================
|
||||
0 Trigger display refresh
|
||||
1 Trigger Wifi channel switch
|
||||
2 Trigger send payload cycle
|
||||
3 Trigger housekeeping cycle
|
||||
================================
|
||||
0 triggers display refresh
|
||||
1 triggers Wifi channel switch
|
||||
2 triggers send payload cycle
|
||||
3 triggers housekeeping cycle
|
||||
|
||||
RTC hardware timer (if present)
|
||||
================================
|
||||
triggers IF482 clock generator
|
||||
|
||||
*/
|
||||
|
||||
@@ -147,6 +152,13 @@ void setup() {
|
||||
strcat_P(features, " PSRAM");
|
||||
#endif
|
||||
|
||||
// set low power mode to off
|
||||
#ifdef HAS_LOWPOWER_SWITCH
|
||||
pinMode(HAS_LED, OUTPUT);
|
||||
digitalWrite(HAS_LOWPOWER_SWITCH, HIGH);
|
||||
strcat_P(features, " LPWR");
|
||||
#endif
|
||||
|
||||
// initialize leds
|
||||
#if (HAS_LED != NOT_A_PIN)
|
||||
pinMode(HAS_LED, OUTPUT);
|
||||
@@ -161,7 +173,7 @@ void setup() {
|
||||
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
// start led loop
|
||||
ESP_LOGI(TAG, "Starting LEDloop...");
|
||||
ESP_LOGI(TAG, "Starting LED Controller...");
|
||||
xTaskCreatePinnedToCore(ledLoop, // task function
|
||||
"ledloop", // name of task
|
||||
1024, // stack size of task
|
||||
@@ -171,7 +183,26 @@ void setup() {
|
||||
0); // CPU core
|
||||
#endif
|
||||
|
||||
// initialize wifi antenna
|
||||
// initialize RTC
|
||||
#ifdef HAS_RTC
|
||||
strcat_P(features, " RTC");
|
||||
assert(rtc_init());
|
||||
sync_rtctime();
|
||||
#ifdef HAS_IF482
|
||||
strcat_P(features, " IF482");
|
||||
assert(if482_init());
|
||||
ESP_LOGI(TAG, "Starting IF482 Generator...");
|
||||
xTaskCreatePinnedToCore(if482_loop, // task function
|
||||
"if482loop", // name of task
|
||||
2048, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
3, // priority of the task
|
||||
&IF482Task, // task handle
|
||||
0); // CPU core
|
||||
#endif // HAS_IF482
|
||||
#endif // HAS_RTC
|
||||
|
||||
// initialize wifi antenna
|
||||
#ifdef HAS_ANTENNA_SWITCH
|
||||
strcat_P(features, " ANT");
|
||||
antenna_init();
|
||||
@@ -233,7 +264,7 @@ void setup() {
|
||||
#ifdef HAS_GPS
|
||||
strcat_P(features, " GPS");
|
||||
if (gps_init()) {
|
||||
ESP_LOGI(TAG, "Starting GPSloop...");
|
||||
ESP_LOGI(TAG, "Starting GPS Feed...");
|
||||
xTaskCreatePinnedToCore(gps_loop, // task function
|
||||
"gpsloop", // name of task
|
||||
2048, // stack size of task
|
||||
@@ -312,7 +343,7 @@ void setup() {
|
||||
ESP_LOGI(TAG, "Features:%s", features);
|
||||
|
||||
#ifdef HAS_LORA
|
||||
// output LoRaWAN keys to console
|
||||
// output LoRaWAN keys to console
|
||||
#ifdef VERBOSE
|
||||
showLoraKeys();
|
||||
#endif
|
||||
@@ -327,7 +358,7 @@ void setup() {
|
||||
get_salt(); // get new 16bit for salting hashes
|
||||
|
||||
// start state machine
|
||||
ESP_LOGI(TAG, "Starting IRQ Handler...");
|
||||
ESP_LOGI(TAG, "Starting Interrupt Handler...");
|
||||
xTaskCreatePinnedToCore(irqHandler, // task function
|
||||
"irqhandler", // name of task
|
||||
4096, // stack size of task
|
||||
@@ -346,11 +377,11 @@ void setup() {
|
||||
&wifiSwitchTask, // task handle
|
||||
0); // CPU core
|
||||
|
||||
// initialize bme
|
||||
// initialize bme
|
||||
#ifdef HAS_BME
|
||||
strcat_P(features, " BME");
|
||||
if (bme_init()) {
|
||||
ESP_LOGI(TAG, "Starting BMEloop...");
|
||||
ESP_LOGI(TAG, "Starting Bluetooth sniffer...");
|
||||
xTaskCreatePinnedToCore(bme_loop, // task function
|
||||
"bmeloop", // name of task
|
||||
2048, // stack size of task
|
||||
@@ -361,7 +392,8 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// start timer triggered interrupts
|
||||
assert(irqHandlerTask != NULL); // has interrupt handler task started?
|
||||
// start timer triggered interrupts
|
||||
ESP_LOGI(TAG, "Starting Interrupts...");
|
||||
#ifdef HAS_DISPLAY
|
||||
timerAlarmEnable(displaytimer);
|
||||
@@ -370,7 +402,7 @@ void setup() {
|
||||
timerAlarmEnable(homeCycle);
|
||||
timerAlarmEnable(channelSwitch);
|
||||
|
||||
// start button interrupt
|
||||
// start button interrupt
|
||||
#ifdef HAS_BUTTON
|
||||
#ifdef BUTTON_PULLUP
|
||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
|
||||
@@ -379,6 +411,14 @@ void setup() {
|
||||
#endif
|
||||
#endif // HAS_BUTTON
|
||||
|
||||
// start RTC interrupt
|
||||
#if defined HAS_IF482 && defined HAS_RTC
|
||||
// setup external interupt for active low RTC INT pin
|
||||
assert(IF482Task != NULL); // has if482loop task started?
|
||||
ESP_LOGI(TAG, "Starting IF482 output...");
|
||||
attachInterrupt(digitalPinToInterrupt(RTC_INT), IF482IRQ, FALLING);
|
||||
#endif
|
||||
|
||||
} // setup()
|
||||
|
||||
void loop() {
|
||||
|
||||
+8
-3
@@ -81,8 +81,13 @@
|
||||
#define OTA_MIN_BATT 3600 // minimum battery level for OTA [millivolt]
|
||||
#define RESPONSE_TIMEOUT_MS 60000 // firmware binary server connection timeout [milliseconds]
|
||||
|
||||
// setting for syncing time of node
|
||||
//#define TIME_SYNC_INTERVAL 60 // sync time each ... minutes [default = 60], comment out means off
|
||||
// settings for syncing time of node and external time sources
|
||||
#define TIME_SYNC_INTERVAL 60 // sync time each ... minutes with external source [default = 60], comment out means off
|
||||
#define TIME_SYNC_INTERVAL_RTC 5 // sync time each ... minutes with RTC [default = 5], comment out means off
|
||||
#define IF482_OFFSET 984 // 1sec minus IF482 serial transmit time [ms]: e.g. 9 bits * 17 bytes * 1/9600 bps = 16ms
|
||||
// time zone, see https://github.com/JChristensen/Timezone/blob/master/examples/WorldClock/WorldClock.ino
|
||||
#define DAYLIGHT_TIME {"CEST", Last, Sun, Mar, 2, 120} // Central European Summer Time
|
||||
#define STANDARD_TIME {"CET ", Last, Sun, Oct, 3, 60} // Central European Standard Time
|
||||
|
||||
// LMIC settings
|
||||
// moved to src/lmic_config.h
|
||||
// moved to src/lmic_config.h
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
#ifdef HAS_RTC
|
||||
|
||||
#include "rtctime.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
|
||||
|
||||
// set Time Zone, fetch user setting from paxcounter.conf
|
||||
TimeChangeRule myDST = DAYLIGHT_TIME;
|
||||
TimeChangeRule mySTD = STANDARD_TIME;
|
||||
Timezone myTZ(myDST, mySTD);
|
||||
|
||||
// initialize RTC
|
||||
int rtc_init(void) {
|
||||
|
||||
// return = 0 -> error / return = 1 -> success
|
||||
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
|
||||
Wire.begin(HAS_RTC);
|
||||
Rtc.Begin();
|
||||
|
||||
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
|
||||
|
||||
if (!Rtc.IsDateTimeValid()) {
|
||||
ESP_LOGW(TAG,
|
||||
"RTC has no valid RTC date/time, setting to compilation date");
|
||||
Rtc.SetDateTime(compiled);
|
||||
}
|
||||
|
||||
if (!Rtc.GetIsRunning()) {
|
||||
ESP_LOGI(TAG, "RTC not running, starting now");
|
||||
Rtc.SetIsRunning(true);
|
||||
}
|
||||
|
||||
RtcDateTime now = Rtc.GetDateTime();
|
||||
|
||||
if (now < compiled) {
|
||||
ESP_LOGI(TAG, "RTC date/time is older than compilation date, updating");
|
||||
Rtc.SetDateTime(compiled);
|
||||
}
|
||||
|
||||
// configure RTC chip
|
||||
Rtc.Enable32kHzPin(false);
|
||||
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
|
||||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
|
||||
goto error;
|
||||
}
|
||||
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
ESP_LOGI(TAG, "RTC initialized");
|
||||
return 1;
|
||||
|
||||
error:
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
return 0;
|
||||
|
||||
} // rtc_init()
|
||||
|
||||
int set_rtctime(uint32_t UTCTime) {
|
||||
// return = 0 -> error / return = 1 -> success
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
Rtc.SetDateTime(RtcDateTime(UTCTime));
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} // set_rtctime()
|
||||
|
||||
int set_rtctime(RtcDateTime t) {
|
||||
// return = 0 -> error / return = 1 -> success
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
Rtc.SetDateTime(t);
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} // set_rtctime()
|
||||
|
||||
time_t get_rtctime(void) {
|
||||
// never call now() in this function, this would cause a recursion!
|
||||
time_t tt = 0;
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
if (!Rtc.IsDateTimeValid()) {
|
||||
ESP_LOGW(TAG, "RTC has no confident time");
|
||||
} else {
|
||||
RtcDateTime t = Rtc.GetDateTime();
|
||||
tt = t.Epoch32Time();
|
||||
}
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
return tt;
|
||||
}
|
||||
return tt;
|
||||
} // get_rtctime()
|
||||
|
||||
void sync_rtctime(void) {
|
||||
if (timeStatus() != timeSet) { // do we need time sync?
|
||||
time_t t = get_rtctime();
|
||||
if (t) { // have we got a valid time from RTC?
|
||||
setTime(t);
|
||||
time_t tt = myTZ.toLocal(t);
|
||||
ESP_LOGI(TAG, "RTC has set system time to %02d/%02d/%d %02d:%02d:%02d",
|
||||
month(tt), day(tt), year(tt), hour(tt), minute(tt), second(tt));
|
||||
} else
|
||||
ESP_LOGW(TAG, "System time was not synced");
|
||||
}
|
||||
|
||||
#ifdef TIME_SYNC_INTERVAL_RTC
|
||||
setSyncProvider(&get_rtctime); // does not sync if callback function returns 0
|
||||
if (timeStatus() != timeSet)
|
||||
ESP_LOGI("Unable to sync with the RTC");
|
||||
else
|
||||
ESP_LOGI("RTC has set the system time");
|
||||
setSyncInterval(TIME_SYNC_INTERVAL_RTC);
|
||||
#endif
|
||||
|
||||
} // sync_rtctime;
|
||||
|
||||
float get_rtctemp(void) {
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
RtcTemperature temp = Rtc.GetTemperature();
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
return temp.AsFloatDegC();
|
||||
} // while
|
||||
return 0;
|
||||
} // get_rtc()
|
||||
|
||||
#endif // HAS_RTC
|
||||
Reference in new issue
Block a user