Merge branch 'development' of https://github.com/cyberman54/ESP32-Paxcounter into development
This commit is contained in:
commit
014e6cd4a5
53 files changed
+1239
-547
No files matched your search
@@ -37,7 +37,7 @@ function Decoder(bytes, port) {
|
||||
|
||||
if (port === 3) {
|
||||
// device config data
|
||||
return decode(bytes, [uint8, uint8, int16, uint8, uint8, uint8, uint8, bitmap1, bitmap2, version], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags', 'payloadmask', 'version']);
|
||||
return decode(bytes, [uint8, uint8, int16, uint8, uint8, uint8, uint8, bitmap1, bitmap2, version], ['loradr', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags', 'payloadmask', 'version']);
|
||||
}
|
||||
|
||||
if (port === 4) {
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "globals.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
esp_adc_cal_characteristics_t *adc_characs =
|
||||
(esp_adc_cal_characteristics_t *)calloc(
|
||||
1, sizeof(esp_adc_cal_characteristics_t));
|
||||
|
||||
static const adc1_channel_t adc_channel = BAT_MEASURE_ADC;
|
||||
static const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||
static const adc_unit_t unit = ADC_UNIT_1;
|
||||
#endif
|
||||
|
||||
void calibrate_voltage(void) {
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
// configure ADC
|
||||
ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12));
|
||||
ESP_ERROR_CHECK(adc1_config_channel_atten(adc_channel, atten));
|
||||
// calibrate ADC
|
||||
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(
|
||||
unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_characs);
|
||||
// show ADC characterization base
|
||||
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||
ESP_LOGI(TAG,
|
||||
"ADC characterization based on Two Point values stored in eFuse");
|
||||
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||
ESP_LOGI(TAG,
|
||||
"ADC characterization based on reference voltage stored in eFuse");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "ADC characterization based on default reference voltage");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t read_voltage() {
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
// multisample ADC
|
||||
uint32_t adc_reading = 0;
|
||||
for (int i = 0; i < NO_OF_SAMPLES; i++) {
|
||||
adc_reading += adc1_get_raw(adc_channel);
|
||||
}
|
||||
adc_reading /= NO_OF_SAMPLES;
|
||||
// Convert ADC reading to voltage in mV
|
||||
uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_characs);
|
||||
#ifdef BAT_VOLTAGE_DIVIDER
|
||||
voltage *= BAT_VOLTAGE_DIVIDER;
|
||||
#endif
|
||||
|
||||
#ifdef BAT_MEASURE_EN // turn ext. power off
|
||||
digitalWrite(EXT_POWER_SW, EXT_POWER_OFF);
|
||||
#endif
|
||||
|
||||
return (uint16_t)voltage;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool batt_sufficient() {
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
uint16_t volts = read_voltage();
|
||||
return ((volts < 1000) ||
|
||||
(volts > OTA_MIN_BATT)); // no battery or battery sufficient
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
+3
-1
@@ -143,7 +143,9 @@ int checkIaqSensorStatus(void) {
|
||||
|
||||
// store current BME sensor data in struct
|
||||
void bme_storedata(bmeStatus_t *bme_store) {
|
||||
if (I2C_MUTEX_LOCK()) { // block i2c bus access
|
||||
|
||||
if ((cfg.payloadmask & MEMS_DATA) &&
|
||||
(I2C_MUTEX_LOCK())) { // block i2c bus access
|
||||
|
||||
#ifdef HAS_BME680
|
||||
if (iaqSensor.run()) { // if new data is available
|
||||
|
||||
+21
-16
@@ -8,16 +8,21 @@ static const char TAG[] = "flash";
|
||||
nvs_handle my_handle;
|
||||
esp_err_t err;
|
||||
|
||||
#define PAYLOADMASK \
|
||||
((GPS_DATA | ALARM_DATA | MEMS_DATA | COUNT_DATA | SENSOR1_DATA | \
|
||||
SENSOR2_DATA | SENSOR3_DATA) & \
|
||||
~BATT_DATA)
|
||||
|
||||
// populate cfg vars with factory settings
|
||||
void defaultConfig() {
|
||||
cfg.lorasf = LORASFDEFAULT; // 7-12, initial lora sf, see pacounter.conf
|
||||
cfg.txpower = 15; // 2-15, lora tx power
|
||||
cfg.adrmode = 1; // 0=disabled, 1=enabled
|
||||
cfg.screensaver = 0; // 0=disabled, 1=enabled
|
||||
cfg.screenon = 1; // 0=disabled, 1=enabled
|
||||
cfg.countermode = 0; // 0=cyclic, 1=cumulative, 2=cyclic confirmed
|
||||
cfg.rssilimit = 0; // threshold for rssilimiter, negative value!
|
||||
cfg.sendcycle = SENDCYCLE; // payload send cycle [seconds/2]
|
||||
cfg.loradr = LORADRDEFAULT; // 0-15, lora datarate, see pacounter.conf
|
||||
cfg.txpower = LORATXPOWDEFAULT; // 0-15, lora tx power
|
||||
cfg.adrmode = 1; // 0=disabled, 1=enabled
|
||||
cfg.screensaver = 0; // 0=disabled, 1=enabled
|
||||
cfg.screenon = 1; // 0=disabled, 1=enabled
|
||||
cfg.countermode = 0; // 0=cyclic, 1=cumulative, 2=cyclic confirmed
|
||||
cfg.rssilimit = 0; // threshold for rssilimiter, negative value!
|
||||
cfg.sendcycle = SENDCYCLE; // payload send cycle [seconds/2]
|
||||
cfg.wifichancycle =
|
||||
WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100]
|
||||
cfg.blescantime =
|
||||
@@ -29,7 +34,7 @@ void defaultConfig() {
|
||||
cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
|
||||
cfg.monitormode = 0; // 0=disabled, 1=enabled
|
||||
cfg.runmode = 0; // 0=normal, 1=update
|
||||
cfg.payloadmask = 0xFF; // all payload switched on
|
||||
cfg.payloadmask = PAYLOADMASK; // all payload switched on
|
||||
cfg.bsecstate[BSEC_MAX_STATE_BLOB_SIZE] = {
|
||||
0}; // init BSEC state for BME680 sensor
|
||||
|
||||
@@ -92,9 +97,9 @@ void saveConfig() {
|
||||
strcmp(storedversion, cfg.version) != 0)
|
||||
nvs_set_str(my_handle, "version", cfg.version);
|
||||
|
||||
if (nvs_get_i8(my_handle, "lorasf", &flash8) != ESP_OK ||
|
||||
flash8 != cfg.lorasf)
|
||||
nvs_set_i8(my_handle, "lorasf", cfg.lorasf);
|
||||
if (nvs_get_i8(my_handle, "loradr", &flash8) != ESP_OK ||
|
||||
flash8 != cfg.loradr)
|
||||
nvs_set_i8(my_handle, "loradr", cfg.loradr);
|
||||
|
||||
if (nvs_get_i8(my_handle, "txpower", &flash8) != ESP_OK ||
|
||||
flash8 != cfg.txpower)
|
||||
@@ -217,11 +222,11 @@ void loadConfig() {
|
||||
ESP_LOGI(TAG, "bsecstate = %d", cfg.bsecstate[BSEC_MAX_STATE_BLOB_SIZE]);
|
||||
};
|
||||
|
||||
if (nvs_get_i8(my_handle, "lorasf", &flash8) == ESP_OK) {
|
||||
cfg.lorasf = flash8;
|
||||
ESP_LOGI(TAG, "lorasf = %d", flash8);
|
||||
if (nvs_get_i8(my_handle, "loradr", &flash8) == ESP_OK) {
|
||||
cfg.loradr = flash8;
|
||||
ESP_LOGI(TAG, "loradr = %d", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "lorasf set to default %d", cfg.lorasf);
|
||||
ESP_LOGI(TAG, "loradr set to default %d", cfg.loradr);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -30,6 +30,9 @@ void doHousekeeping() {
|
||||
#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));
|
||||
#endif
|
||||
#if (HAS_GPS)
|
||||
ESP_LOGD(TAG, "Gpsloop %d bytes left | Taskstate = %d",
|
||||
@@ -52,9 +55,15 @@ void doHousekeeping() {
|
||||
#endif
|
||||
|
||||
// read battery voltage into global variable
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
#if (defined BAT_MEASURE_ADC || defined HAS_PMU)
|
||||
batt_voltage = read_voltage();
|
||||
ESP_LOGI(TAG, "Voltage: %dmV", batt_voltage);
|
||||
if (batt_voltage == 0xffff)
|
||||
ESP_LOGI(TAG, "Battery: external power");
|
||||
else
|
||||
ESP_LOGI(TAG, "Battery: %dmV", batt_voltage);
|
||||
#ifdef HAS_PMU
|
||||
AXP192_showstatus();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// display BME680/280 sensor data
|
||||
|
||||
+17
-32
@@ -10,15 +10,17 @@ Display-Mask (128 x 64 pixel):
|
||||
0|PAX:aabbccddee
|
||||
1|PAX:aabbccddee
|
||||
2|B:a.bcV Sats:ab
|
||||
3|BLTH:abcde SF:ab
|
||||
3|BLTH:abcde SFab
|
||||
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
|
||||
|
||||
line 6: * = char {L|G|R|?} indicates time source,
|
||||
inverse = clock controller is active,
|
||||
pulsed = pps input signal is active
|
||||
|
||||
line 7: y = LMIC event message; ab = payload queue length
|
||||
|
||||
*/
|
||||
|
||||
@@ -30,19 +32,6 @@ line 7: y = Text for LMIC status; ab = payload queue
|
||||
|
||||
HAS_DISPLAY u8x8(MY_OLED_RST, MY_OLED_SCL, MY_OLED_SDA);
|
||||
|
||||
// helper string for converting LoRa spread factor values
|
||||
#if defined(CFG_eu868)
|
||||
const char lora_datarate[] = {"1211100908077BFSNA"};
|
||||
#elif defined(CFG_us915)
|
||||
const char lora_datarate[] = {"100908078CNA121110090807"};
|
||||
#elif defined(CFG_as923)
|
||||
const char lora_datarate[] = {"1211100908077BFSNA"};
|
||||
#elif defined(CFG_au921)
|
||||
const char lora_datarate[] = {"1211100908078CNA1211109C8C7C"};
|
||||
#elif defined(CFG_in866)
|
||||
const char lora_datarate[] = {"121110090807FSNA"};
|
||||
#endif
|
||||
|
||||
// helper arry for converting month values to text
|
||||
const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
@@ -188,9 +177,12 @@ void draw_page(time_t t, uint8_t page) {
|
||||
case 0:
|
||||
|
||||
// update Battery status (line 2)
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
#if (defined BAT_MEASURE_ADC || defined HAS_PMU)
|
||||
u8x8.setCursor(0, 2);
|
||||
u8x8.printf("B:%.2fV", batt_voltage / 1000.0);
|
||||
if (batt_voltage == 0xffff)
|
||||
u8x8.printf("B:USB ");
|
||||
else
|
||||
u8x8.printf("B:%.2fV", batt_voltage / 1000.0);
|
||||
#endif
|
||||
|
||||
// update GPS status (line 2)
|
||||
@@ -215,13 +207,11 @@ void draw_page(time_t t, uint8_t page) {
|
||||
#endif
|
||||
|
||||
#if (HAS_LORA)
|
||||
u8x8.setCursor(11, 3);
|
||||
u8x8.printf("SF:");
|
||||
if (cfg.adrmode) // if ADR=on then display SF value inverse
|
||||
u8x8.setCursor(12, 3);
|
||||
if (!cfg.adrmode) // if ADR=off then display SF value inverse
|
||||
u8x8.setInverseFont(1);
|
||||
u8x8.printf("%c%c", lora_datarate[LMIC.datarate * 2],
|
||||
lora_datarate[LMIC.datarate * 2 + 1]);
|
||||
if (cfg.adrmode) // switch off inverse if it was turned on
|
||||
u8x8.printf("%-4s", getSfName(updr2rps(LMIC.datarate)));
|
||||
if (!cfg.adrmode) // switch off inverse if it was turned on
|
||||
u8x8.setInverseFont(0);
|
||||
#endif // HAS_LORA
|
||||
|
||||
@@ -254,17 +244,13 @@ void draw_page(time_t t, uint8_t page) {
|
||||
#endif // HAS_DCF77 || HAS_IF482
|
||||
if (timeSource != _unsynced)
|
||||
u8x8.printf(" %2d.%3s", day(t), printmonth[month(t)]);
|
||||
#else // update LoRa status display
|
||||
#if (HAS_LORA)
|
||||
u8x8.printf("%-16s", display_line6);
|
||||
#endif
|
||||
|
||||
#endif // TIME_SYNC_INTERVAL
|
||||
|
||||
#if (HAS_LORA)
|
||||
// line 7: update LMiC event display
|
||||
u8x8.setCursor(0, 7);
|
||||
u8x8.printf("%-14s", display_line7);
|
||||
u8x8.printf("%-14s", lmic_event_msg);
|
||||
|
||||
// update LoRa send queue display
|
||||
msgWaiting = uxQueueMessagesWaiting(LoraSendQueue);
|
||||
@@ -274,7 +260,6 @@ void draw_page(time_t t, uint8_t page) {
|
||||
u8x8.printf("%-2s", msgWaiting == SEND_QUEUE_SIZE ? "<>" : buff);
|
||||
} else
|
||||
u8x8.printf(" ");
|
||||
|
||||
#endif // HAS_LORA
|
||||
|
||||
break; // page0
|
||||
|
||||
+9
-9
@@ -90,13 +90,12 @@ time_t fetch_gpsTime(uint16_t *msec) {
|
||||
// poll NMEA $GPZDA 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
|
||||
|
||||
// wait for gps NMEA answer
|
||||
//vTaskDelay(tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL));
|
||||
|
||||
// did we get a current time?
|
||||
if (gpstime.isUpdated() && gpstime.isValid()) {
|
||||
|
||||
@@ -104,7 +103,8 @@ time_t fetch_gpsTime(uint16_t *msec) {
|
||||
|
||||
String rawtime = gpstime.value();
|
||||
uint32_t time_bcd = rawtime.toFloat() * 100;
|
||||
uint32_t delay_ms = gpstime.age() + nmea_txDelay_ms + NMEA_COMPENSATION_FACTOR;
|
||||
uint32_t delay_ms =
|
||||
gpstime.age() + nmea_txDelay_ms + NMEA_COMPENSATION_FACTOR;
|
||||
uint8_t year =
|
||||
CalendarYrToTm(gps.date.year()); // year offset from 1970 in microTime.h
|
||||
|
||||
@@ -138,7 +138,7 @@ void gps_loop(void *pvParameters) {
|
||||
|
||||
while (1) {
|
||||
|
||||
if (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()) {
|
||||
@@ -153,10 +153,10 @@ void gps_loop(void *pvParameters) {
|
||||
#endif
|
||||
} // if
|
||||
|
||||
// show NMEA data in verbose mode, useful for debugging GPS
|
||||
ESP_LOGV(TAG, "GPS NMEA data: passed %u / failed: %u / with fix: %u",
|
||||
gps.passedChecksum(), gps.failedChecksum(),
|
||||
gps.sentencesWithFix());
|
||||
// show NMEA data in verbose mode, useful for debugging GPS, bu tvery noisy
|
||||
//ESP_LOGV(TAG, "GPS NMEA data: passed %u / failed: %u / with fix: %u",
|
||||
// gps.passedChecksum(), gps.failedChecksum(),
|
||||
// gps.sentencesWithFix());
|
||||
|
||||
delay(2); // yield to CPU
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
#define CFG_sx1276_radio 1
|
||||
|
||||
#define HAS_LED (22) // Green LED on board
|
||||
#define HAS_RGB_LED (2) // WS2812B RGB LED on board
|
||||
#define HAS_RGB_LED SmartLed rgb_led(LED_WS2812, 1, GPIO_NUM_2) // WS2812B RGB LED on board
|
||||
#define HAS_BUTTON (0) // button "FLASH" on board
|
||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
|
||||
#define CFG_sx1272_radio 1
|
||||
#define HAS_LED NOT_A_PIN // FiPy has no on board LED, so we use RGB LED
|
||||
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
|
||||
#define HAS_RGB_LED SmartLed rgb_led(LED_WS2812, 1, GPIO_NUM_0) // WS2812B RGB LED on GPIO0
|
||||
#define BOARD_HAS_PSRAM // use extra 4MB extern RAM
|
||||
|
||||
// Pins for LORA chip SPI interface, reset line and interrupt lines
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@
|
||||
|
||||
#define HAS_LED (21) // on board LED
|
||||
#define HAS_BUTTON (39) // on board button
|
||||
#define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0
|
||||
#define HAS_RGB_LED SmartLed rgb_led(LED_WS2812, 1, GPIO_NUM_0) // WS2812B RGB LED on GPIO0
|
||||
|
||||
// GPS settings
|
||||
#define HAS_GPS 1 // use on board GPS
|
||||
|
||||
+6
-1
@@ -20,8 +20,13 @@
|
||||
#define HAS_LED LED_BUILTIN // white LED on board
|
||||
#define HAS_BUTTON KEY_BUILTIN // button "PROG" on board
|
||||
|
||||
// caveat: activating ADC2 conflicts with Wifi in current arduino-esp32
|
||||
// see https://github.com/espressif/arduino-esp32/issues/3222
|
||||
// thus we must waiver of battery monitoring
|
||||
//#define BAT_MEASURE_ADC ADC2_GPIO13_CHANNEL // battery probe GPIO pin
|
||||
//#define BAT_VOLTAGE_DIVIDER 4 // voltage divider 220k/100k on board
|
||||
//#define BAT_MEASURE_ADC_UNIT 2 // ADC 2
|
||||
//#define BAT_VOLTAGE_DIVIDER 2 // voltage divider 220k/100k on board
|
||||
|
||||
#define EXT_POWER_SW Vext // switches battery power, Vext control 0 = on / 1 = off
|
||||
#define EXT_POWER_ON 0
|
||||
//#define EXT_POWER_OFF 1
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
|
||||
#define HAS_LED 22 // ESP32 GPIO12 (pin22) On Board LED
|
||||
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
||||
#define HAS_RGB_LED 13 // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED
|
||||
#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
|
||||
#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define HAS_LED NOT_A_PIN // Led os on same pin as Lora SS pin, to avoid problems, we don't use it
|
||||
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
||||
// Anyway shield is on over the LoLin32 board, so we won't be able to see this LED
|
||||
#define HAS_RGB_LED 13 // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED
|
||||
#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
|
||||
#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
|
||||
#define CFG_sx1272_radio 1
|
||||
#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED
|
||||
#define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0
|
||||
#define HAS_RGB_LED SmartLed rgb_led(LED_WS2812, 1, GPIO_NUM_0) // WS2812B RGB LED on GPIO0 (P2)
|
||||
|
||||
// Note: Pins for LORA chip SPI interface come from board file pins_arduino.h
|
||||
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@
|
||||
//#define SPI_CS GPIO_NUM_36
|
||||
|
||||
#define CFG_sx1276_radio 1
|
||||
//#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED
|
||||
#define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0 (P2)
|
||||
#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED
|
||||
#define HAS_RGB_LED SmartLed rgb_led(LED_WS2812, 1, GPIO_NUM_0) // WS2812B RGB LED on GPIO0 (P2)
|
||||
#define BOARD_HAS_PSRAM // use extra 4MB extern RAM
|
||||
|
||||
// Note: Pins for LORA chip SPI interface come from board file pins_arduino.h
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
|
||||
#define HAS_LED 13 // ESP32 GPIO12 (pin22) On Board LED
|
||||
//#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
||||
//#define HAS_RGB_LED 13 // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED
|
||||
//#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
|
||||
//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// clang-format off
|
||||
// upload_speed 921600
|
||||
// board esp32dev
|
||||
|
||||
|
||||
#ifndef _TINYPICO_H
|
||||
#define _TINYPICO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Hardware related definitions for crowdsupply tinypico board
|
||||
|
||||
#define HAS_LED NOT_A_PIN // Green LED on board
|
||||
#define HAS_RGB_LED Apa102 rgb_led(1, GPIO_NUM_12, GPIO_NUM_2) // APA102 RGB LED on board
|
||||
|
||||
//#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
#define BAT_VOLTAGE_DIVIDER 2.7625f // voltage divider 160k/442k on board
|
||||
#define BOARD_HAS_PSRAM // use extra 4MB external RAM
|
||||
#define LED_POWER_SW (13) // switches LED power
|
||||
#define LED_POWER_ON 0 // switch on transistor for LED power
|
||||
#define LED_POWER_OFF 1
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
// clang-format off
|
||||
// upload_speed 921600
|
||||
// board esp32dev
|
||||
|
||||
|
||||
#ifndef _TINYPICO_H
|
||||
#define _TINYPICO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Hardware related definitions for crowdsupply tinypico board
|
||||
// for operating a 96x16 shift register LED matrix display
|
||||
|
||||
#define HAS_LED NOT_A_PIN // Green LED on board
|
||||
#define HAS_RGB_LED Apa102 rgb_led(1, GPIO_NUM_12, GPIO_NUM_2) // APA102 RGB LED on board
|
||||
|
||||
//#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
#define BAT_VOLTAGE_DIVIDER 2.7625f // voltage divider 160k/442k on board
|
||||
#define BOARD_HAS_PSRAM // use extra 4MB external RAM
|
||||
#define LED_POWER_SW (13) // switches LED power
|
||||
#define LED_POWER_ON 0 // switch on transistor for LED power
|
||||
#define LED_POWER_OFF 1
|
||||
|
||||
// LED Matrix display settings
|
||||
#define HAS_MATRIX_DISPLAY 1 // Uncomment to enable LED matrix display output
|
||||
#define LED_MATRIX_WIDTH (32*2) // Width (cols) in pixels (LEDs) of your display, must be 32X
|
||||
#define LED_MATRIX_HEIGHT (16*1) // Height (rows) in pixels (LEDs) of your display, must be 16X
|
||||
|
||||
// Explanation of pin signals see https://learn.adafruit.com/32x16-32x32-rgb-led-matrix/new-wiring
|
||||
#define MATRIX_DISPLAY_SCAN_US 500 // Matrix display scan rate in microseconds (1ms is about 'acceptable')
|
||||
#define LED_MATRIX_LATCHPIN 32 // LAT (or STB = Strobe)
|
||||
#define LED_MATRIX_CLOCKPIN 33 // CLK
|
||||
#define LED_MATRIX_EN_74138 21 // EN (or OE)
|
||||
#define LED_MATRIX_LA_74138 23 // LA (or A)
|
||||
#define LED_MATRIX_LB_74138 19 // LB (or B)
|
||||
#define LED_MATRIX_LC_74138 18 // LC (or C)
|
||||
#define LED_MATRIX_LD_74138 5 // LD (or D)
|
||||
#define LED_MATRIX_DATA_R1 22 // R1 (or R0)
|
||||
|
||||
// CLK: The clock signal moves the data bits from pin R1 ("red") in the shift registers
|
||||
// LAT: The latch signal enables LEDs according to the shift register's contents
|
||||
// Line Selects: LA, LB, LC, LD select which rows of the display are currently lit (0 .. 15)
|
||||
// OE: Output enable switches the LEDs on/off while transitioning from one row to the next
|
||||
|
||||
#endif
|
||||
+3
-4
@@ -17,7 +17,6 @@
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
|
||||
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
|
||||
#define BOARD_HAS_PSRAM // use extra 4MB external RAM
|
||||
#define HAS_BUTTON GPIO_NUM_39 // on board button (next to reset)
|
||||
#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
|
||||
@@ -29,9 +28,9 @@
|
||||
|
||||
// enable only if device has these sensors, otherwise comment these lines
|
||||
// BME680 sensor on I2C bus
|
||||
//#define HAS_BME 1 // Enable BME sensors in general
|
||||
//#define HAS_BME680 SDA, SCL
|
||||
//#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // !! connect SDIO of BME680 to GND !!
|
||||
#define HAS_BME 1 // Enable BME sensors in general
|
||||
#define HAS_BME680 SDA, SCL
|
||||
#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // !! connect SDIO of BME680 to GND !!
|
||||
|
||||
// display (if connected)
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// clang-format off
|
||||
// upload_speed 921600
|
||||
// board ttgo-t-beam
|
||||
|
||||
#ifndef _TTGOBEAM_H
|
||||
#define _TTGOBEAM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
Hardware related definitions for TTGO T-Beam board
|
||||
(only) for newer T-Beam version T22_V10
|
||||
pinouts taken from https://github.com/lewisxhe/TTGO-T-Beam
|
||||
|
||||
/// Button functions: ///
|
||||
Power, short press -> set device on (toggles display while device is on)
|
||||
Power, long press -> set device off
|
||||
User, short press -> flip display page
|
||||
User, long press -> send LORA message
|
||||
Reset -> reset device
|
||||
*/
|
||||
|
||||
//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
#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
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
|
||||
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
|
||||
#define HAS_BUTTON GPIO_NUM_38 // middle on board button
|
||||
#define HAS_PMU 1 // AXP192 power management chip
|
||||
#define PMU_INT GPIO_NUM_35 // AXP192 interrupt
|
||||
|
||||
#define HAS_LED NOT_A_PIN
|
||||
|
||||
// GPS settings
|
||||
#define HAS_GPS 1 // use on board GPS
|
||||
#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_34, GPIO_NUM_12 // UBlox NEO 6M
|
||||
#define GPS_INT GPIO_NUM_37 // 30ns accurary timepulse generated by NEO 6M Pin #3
|
||||
|
||||
// enable only if device has these sensors, otherwise comment these lines
|
||||
// BME680 sensor on I2C bus
|
||||
//#define HAS_BME 1 // Enable BME sensors in general
|
||||
//#define HAS_BME680 SDA, SCL
|
||||
//#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // !! connect SDIO of BME680 to GND !!
|
||||
|
||||
// user defined sensors (if connected)
|
||||
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
|
||||
|
||||
//#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
// T-Beam V10 has on board power management by AXP192 PMU chip:
|
||||
//
|
||||
// DCDC1 0.7-3.5V @ 1200mA -> OLED
|
||||
// DCDC3 0.7-3.5V @ 700mA -> ESP32 (keep this on!)
|
||||
// LDO1 30mA -> GPS Backup
|
||||
// LDO2 200mA -> LORA
|
||||
// LDO3 200mA -> GPS
|
||||
|
||||
// Wiring for I2C OLED display:
|
||||
//
|
||||
// Signal Header OLED
|
||||
// 3V3 7 VCC
|
||||
// GND 8 GND
|
||||
// IO22(SCL) 9 SCL
|
||||
// IO21(SDA) 10 SDA
|
||||
//
|
||||
|
||||
*/
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
// LED Matrix display settings
|
||||
#define HAS_MATRIX_DISPLAY 1 // Uncomment to enable LED matrix display output
|
||||
#define LED_MATRIX_WIDTH 64 // Width in pixels (LEDs) of your display
|
||||
#define LED_MATRIX_HEIGHT 16 // Height in pixels (LEDs ) of your display
|
||||
#define LED_MATRIX_WIDTH (32*2) // Width (cols) in pixels (LEDs) of your display, must be 32X
|
||||
#define LED_MATRIX_HEIGHT (16*1) // Height (rows) in pixels (LEDs) of your display, must be 16X
|
||||
|
||||
// Pin numbers work fine for Wemos Lolin32 board (all used pins are on 1 side of the board)
|
||||
// Explanation of pin signals see https://learn.adafruit.com/32x16-32x32-rgb-led-matrix/new-wiring
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// Basic config
|
||||
#include "globals.h"
|
||||
#include "i2cscan.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
int i2c_scan(void) {
|
||||
|
||||
int i2c_ret, addr;
|
||||
int devices = 0;
|
||||
|
||||
ESP_LOGI(TAG, "Starting I2C bus scan...");
|
||||
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
|
||||
for (addr = 8; addr <= 119; addr++) {
|
||||
|
||||
// scan i2c bus with no more to 100KHz
|
||||
Wire.beginTransmission(addr);
|
||||
Wire.write(addr);
|
||||
i2c_ret = Wire.endTransmission();
|
||||
|
||||
if (i2c_ret == 0) {
|
||||
devices++;
|
||||
|
||||
switch (addr) {
|
||||
|
||||
case SSD1306_PRIMARY_ADDRESS:
|
||||
case SSD1306_SECONDARY_ADDRESS:
|
||||
ESP_LOGI(TAG, "0x%X: SSD1306 Display controller", addr);
|
||||
break;
|
||||
|
||||
case BME_PRIMARY_ADDRESS:
|
||||
case BME_SECONDARY_ADDRESS:
|
||||
ESP_LOGI(TAG, "0x%X: Bosch BME MEMS", addr);
|
||||
break;
|
||||
|
||||
case AXP192_PRIMARY_ADDRESS:
|
||||
ESP_LOGI(TAG, "0x%X: AXP192 power management", addr);
|
||||
break;
|
||||
|
||||
case QUECTEL_GPS_PRIMARY_ADDRESS:
|
||||
ESP_LOGI(TAG, "0x%X: Quectel GPS", addr);
|
||||
break;
|
||||
|
||||
case MCP_24AA02E64_PRIMARY_ADDRESS:
|
||||
ESP_LOGI(TAG, "0x%X: 24AA02E64 serial EEPROM", addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGI(TAG, "0x%X: Unknown device", addr);
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
} // for loop
|
||||
|
||||
ESP_LOGI(TAG, "I2C scan done, %u devices found.", devices);
|
||||
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
} else
|
||||
ESP_LOGE(TAG, "I2c bus busy - scan error");
|
||||
|
||||
return devices;
|
||||
}
|
||||
+19
-1
@@ -63,9 +63,15 @@ void irqHandler(void *pvParameters) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// do we have a power event?
|
||||
#if (HAS_PMU)
|
||||
if (InterruptStatus & PMU_IRQ)
|
||||
power_event_IRQ();
|
||||
#endif
|
||||
|
||||
// is time to send the payload?
|
||||
if (InterruptStatus & SENDCYCLE_IRQ)
|
||||
sendCounter();
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +112,18 @@ void IRAM_ATTR ButtonIRQ() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PMU
|
||||
void IRAM_ATTR PMUIRQ() {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
xTaskNotifyFromISR(irqHandlerTask, PMU_IRQ, eSetBits,
|
||||
&xHigherPriorityTaskWoken);
|
||||
|
||||
if (xHigherPriorityTaskWoken)
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
#endif
|
||||
|
||||
void mask_user_IRQ() { xTaskNotify(irqHandlerTask, MASK_IRQ, eSetBits); }
|
||||
|
||||
void unmask_user_IRQ() { xTaskNotify(irqHandlerTask, UNMASK_IRQ, eSetBits); }
|
||||
+1
-1
@@ -14,7 +14,7 @@ unsigned long LEDBlinkStarted = 0; // When (in millis() led blink started)
|
||||
#ifdef HAS_RGB_LED
|
||||
|
||||
// RGB Led instance
|
||||
SmartLed rgb_led(LED_WS2812, 1, HAS_RGB_LED);
|
||||
HAS_RGB_LED;
|
||||
|
||||
float rgb_CalcColor(float p, float q, float t) {
|
||||
if (t < 0.0f)
|
||||
|
||||
+66
-12
@@ -2,13 +2,14 @@
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
#define NUMCHARS 5
|
||||
#define MATRIX_DISPLAY_PAGES (2) // number of display pages
|
||||
#define LINE_DIAGRAM_DIVIDER (2) // scales pax numbers to led rows
|
||||
|
||||
// local Tag for logging
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
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 = myTZ.toLocal(now());
|
||||
|
||||
@@ -16,9 +17,6 @@ LEDMatrix matrix(LED_MATRIX_LA_74138, LED_MATRIX_LB_74138, LED_MATRIX_LC_74138,
|
||||
LED_MATRIX_LD_74138, LED_MATRIX_EN_74138, LED_MATRIX_DATA_R1,
|
||||
LED_MATRIX_LATCHPIN, LED_MATRIX_CLOCKPIN);
|
||||
|
||||
// Display Buffer 128 = 64 * 16 / 8
|
||||
uint8_t displaybuf[LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT / NUMCHARS];
|
||||
|
||||
// --- SELECT YOUR FONT HERE ---
|
||||
const FONT_INFO *ActiveFontInfo = &digital7_18ptFontInfo;
|
||||
// const FONT_INFO *ActiveFontInfo = &arialNarrow_17ptFontInfo;
|
||||
@@ -31,14 +29,21 @@ const FONT_CHAR_INFO *ActiveFontCharInfo = ActiveFontInfo->Descriptors;
|
||||
void init_matrix_display(bool reverse) {
|
||||
ESP_LOGI(TAG, "Initializing LED Matrix display");
|
||||
matrix.begin(displaybuf, LED_MATRIX_WIDTH, LED_MATRIX_HEIGHT);
|
||||
|
||||
if (MatrixDisplayIsOn)
|
||||
matrix.on();
|
||||
else
|
||||
matrix.off();
|
||||
|
||||
if (reverse)
|
||||
matrix.reverse();
|
||||
matrix.clear();
|
||||
DrawNumber(String("0"));
|
||||
matrix.drawPoint(0, LED_MATRIX_HEIGHT - 1, 1);
|
||||
} // init_display
|
||||
|
||||
void refreshTheMatrixDisplay(bool nextPage) {
|
||||
static uint8_t DisplayPage = 0;
|
||||
static uint8_t DisplayPage = 0, col = 0, row = 0;
|
||||
uint8_t level;
|
||||
char buff[16];
|
||||
|
||||
// if Matrixdisplay is switched off we don't refresh it to relax cpu
|
||||
@@ -48,25 +53,60 @@ void refreshTheMatrixDisplay(bool nextPage) {
|
||||
// set display on/off according to current device configuration
|
||||
if (MatrixDisplayIsOn != cfg.screenon) {
|
||||
MatrixDisplayIsOn = cfg.screenon;
|
||||
if (MatrixDisplayIsOn)
|
||||
matrix.on();
|
||||
else
|
||||
matrix.off();
|
||||
}
|
||||
|
||||
if (nextPage) {
|
||||
DisplayPage =
|
||||
(DisplayPage >= MATRIX_DISPLAY_PAGES - 1) ? 0 : (DisplayPage + 1);
|
||||
matrix.clear();
|
||||
col = 0;
|
||||
}
|
||||
|
||||
switch (DisplayPage % MATRIX_DISPLAY_PAGES) {
|
||||
|
||||
// page 0: pax
|
||||
// page 1: time
|
||||
// page 0: number of current pax OR footfall line diagram
|
||||
// page 1: time of day
|
||||
|
||||
case 0:
|
||||
|
||||
if (ulLastNumMacs != macs.size()) {
|
||||
ulLastNumMacs = macs.size();
|
||||
matrix.clear();
|
||||
DrawNumber(String(ulLastNumMacs));
|
||||
if (cfg.countermode == 1)
|
||||
|
||||
{ // cumulative counter mode -> display total number of pax
|
||||
if (ulLastNumMacs != macs.size()) {
|
||||
ulLastNumMacs = macs.size();
|
||||
matrix.clear();
|
||||
DrawNumber(String(ulLastNumMacs));
|
||||
}
|
||||
}
|
||||
|
||||
else { // cyclic counter mode -> plot a line diagram
|
||||
|
||||
if (ulLastNumMacs != macs.size()) {
|
||||
|
||||
// next count cycle?
|
||||
if (macs.size() == 0) {
|
||||
|
||||
// matrix full? then scroll left 1 dot, else increment column
|
||||
if (col < (LED_MATRIX_WIDTH - 1))
|
||||
col++;
|
||||
else
|
||||
ScrollLeft(displaybuf, LED_MATRIX_WIDTH, LED_MATRIX_HEIGHT);
|
||||
|
||||
} else
|
||||
matrix.drawPoint(col, row, 0); // clear current dot
|
||||
|
||||
// scale and set new dot
|
||||
ulLastNumMacs = macs.size();
|
||||
level = ulLastNumMacs / LINE_DIAGRAM_DIVIDER;
|
||||
row = level <= LED_MATRIX_HEIGHT
|
||||
? LED_MATRIX_HEIGHT - 1 - level % LED_MATRIX_HEIGHT
|
||||
: 0;
|
||||
matrix.drawPoint(col, row, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -164,4 +204,18 @@ uint8_t GetCharWidth(char cChar) {
|
||||
return CharDescriptor.width;
|
||||
}
|
||||
|
||||
void ScrollLeft(uint8_t *buf, const uint16_t cols, const uint16_t rows) {
|
||||
uint32_t i, k, idx;
|
||||
const uint32_t x = cols / 8;
|
||||
|
||||
for (k = 0; k < rows; k++) {
|
||||
// scroll a line with x bytes one dot to the left
|
||||
for (i = 0; i < x - 1; ++i) {
|
||||
idx = i + k * x;
|
||||
buf[idx] = (buf[idx] << 1) | ((buf[idx + 1] >> 7) & 1);
|
||||
}
|
||||
buf[idx + 1] <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAS_MATRIX_DISPLAY
|
||||
+23
-25
@@ -2,40 +2,33 @@
|
||||
|
||||
// COUNTRY SETTINGS
|
||||
// --> please check with you local regulations for ISM band frequency use!
|
||||
//
|
||||
// CFG_eu868 EU 863-870 MHz
|
||||
// CFG_us915 US 902-928 MHz
|
||||
// CFG_au921 Australia 915-928 MHz
|
||||
// CFG_as923 Asia 923 MHz
|
||||
// CFG_in866 India 865-867 MHz
|
||||
|
||||
#define CFG_eu868 1
|
||||
//#define CFG_us915 1
|
||||
//#define CFG_in866 1
|
||||
//#define CFG_au921 1
|
||||
//#define CFG_as923 1
|
||||
//#define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP /* for as923-JP */
|
||||
#define CFG_eu868 1 // Europe (high band)
|
||||
//#define CFG_eu433 1 // Europe (low band)
|
||||
//#define CFG_us915 1 // USA, Canada and South America
|
||||
//#define CFG_in866 1 // India
|
||||
//#define CFG_au921 1 // Australia
|
||||
//#define CFG_as923 1 // Asia
|
||||
//#define CFG_cn783 1 // China (high band)
|
||||
//#define CFG_cn490 1 // China (low band)
|
||||
//#define CFG_kr920 1 // Korea
|
||||
|
||||
// LMIC LORAWAN STACK SETTINGS
|
||||
// --> adapt to your device only if necessary
|
||||
|
||||
//#define LMIC_USE_INTERRUPTS 1
|
||||
// use interrupts only if LORA_IRQ and LORA_DIO are connected to interrupt
|
||||
// capable GPIO pins on your board, if not disable interrupts
|
||||
#define LMIC_USE_INTERRUPTS 1
|
||||
|
||||
//time sync via LoRaWAN network, is not yet supported by TTN (LoRaWAN spec v1.0.3)
|
||||
//#define LMIC_ENABLE_DeviceTimeReq 1
|
||||
|
||||
// 16 μs per tick
|
||||
// LMIC requires ticks to be 15.5μs - 100 μs long
|
||||
#define US_PER_OSTICK_EXPONENT 4
|
||||
#define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT)
|
||||
#define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK)
|
||||
// time sync via LoRaWAN network, note: not supported by TTNv2
|
||||
// #define LMIC_ENABLE_DeviceTimeReq 1
|
||||
|
||||
// This tells LMIC to make the receive windows bigger, in case your clock is
|
||||
// faster or slower. This causes the transceiver to be earlier switched on,
|
||||
// so consuming more power. You may sharpen (reduce) this value if you are
|
||||
// limited on battery.
|
||||
// limited on battery.
|
||||
// ATTN: VALUES > 7 WILL CAUSE RECEPTION AND JOIN PROBLEMS WITH HIGH SF RATES
|
||||
#define CLOCK_ERROR_PROCENTAGE 5
|
||||
//#define CLOCK_ERROR_PROCENTAGE 7
|
||||
|
||||
// Set this to 1 to enable some basic debug output (using printf) about
|
||||
// RF settings used during transmission and reception. Set to 2 to
|
||||
@@ -49,6 +42,11 @@
|
||||
// current implementation only works on AVR, though.
|
||||
//#define LMIC_PRINTF_TO Serial
|
||||
|
||||
// Change the SPI clock speed if you encounter errors
|
||||
// communicating with the radio.
|
||||
// The standard range is 125kHz-8MHz, but some boards can go faster.
|
||||
//#define LMIC_SPI_FREQ 1E6
|
||||
|
||||
// Any runtime assertion failures are printed to this serial port (or
|
||||
// any other Print object). If this is unset, any failures just silently
|
||||
// halt execution.
|
||||
@@ -90,7 +88,7 @@
|
||||
// implementation is optimized for speed on 32-bit processors using
|
||||
// fairly big lookup tables, but it takes up big amounts of flash on the
|
||||
// AVR architecture.
|
||||
//#define USE_ORIGINAL_AES
|
||||
#define USE_ORIGINAL_AES
|
||||
//
|
||||
// This selects the AES implementation written by Ideetroon for their
|
||||
// own LoRaWAN library. It also uses lookup tables, but smaller
|
||||
@@ -98,4 +96,4 @@
|
||||
// also about twice as slow as the original).
|
||||
// #define USE_IDEETRON_AES
|
||||
//
|
||||
#define USE_MBEDTLS_AES
|
||||
//#define USE_MBEDTLS_AES
|
||||
+261
-144
@@ -18,9 +18,31 @@ static const char TAG[] = "lora";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
osjob_t sendjob;
|
||||
QueueHandle_t LoraSendQueue;
|
||||
TaskHandle_t lmicTask = NULL;
|
||||
TaskHandle_t lmicTask = NULL, lorasendTask = NULL;
|
||||
|
||||
// table of LORAWAN MAC messages sent by the network to the device
|
||||
// format: opcode, cmdname (max 19 chars), #bytes params
|
||||
// source: LoRaWAN 1.1 Specification (October 11, 2017)
|
||||
static const mac_t MACdn_table[] = {
|
||||
{0x01, "ResetConf", 1}, {0x02, "LinkCheckAns", 2},
|
||||
{0x03, "LinkADRReq", 4}, {0x04, "DutyCycleReq", 1},
|
||||
{0x05, "RXParamSetupReq", 4}, {0x06, "DevStatusReq", 0},
|
||||
{0x07, "NewChannelReq", 5}, {0x08, "RxTimingSetupReq", 1},
|
||||
{0x09, "TxParamSetupReq", 1}, {0x0A, "DlChannelReq", 4},
|
||||
{0x0B, "RekeyConf", 1}, {0x0C, "ADRParamSetupReq", 1},
|
||||
{0x0D, "DeviceTimeAns", 5}, {0x0E, "ForceRejoinReq", 2},
|
||||
{0x0F, "RejoinParamSetupReq", 1}};
|
||||
|
||||
// table of LORAWAN MAC messages sent by the device to the network
|
||||
static const mac_t MACup_table[] = {
|
||||
{0x01, "ResetInd", 1}, {0x02, "LinkCheckReq", 0},
|
||||
{0x03, "LinkADRAns", 1}, {0x04, "DutyCycleAns", 0},
|
||||
{0x05, "RXParamSetupAns", 1}, {0x06, "DevStatusAns", 2},
|
||||
{0x07, "NewChannelAns", 1}, {0x08, "RxTimingSetupAns", 0},
|
||||
{0x09, "TxParamSetupAns", 0}, {0x0A, "DlChannelAns", 1},
|
||||
{0x0B, "RekeyInd", 1}, {0x0C, "ADRParamSetupAns", 0},
|
||||
{0x0D, "DeviceTimeReq", 0}, {0x0F, "RejoinParamSetupAns", 1}};
|
||||
|
||||
class MyHalConfig_t : public Arduino_LMIC::HalConfiguration_t {
|
||||
|
||||
@@ -135,7 +157,7 @@ void get_hard_deveui(uint8_t *pdeveui) {
|
||||
uint8_t i2c_ret;
|
||||
|
||||
// Init this just in case, no more to 100KHz
|
||||
Wire.begin(MY_OLED_SDA, MY_OLED_SCL, 100000);
|
||||
Wire.begin(SDA, SCL, 100000);
|
||||
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
||||
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
||||
i2c_ret = Wire.endTransmission();
|
||||
@@ -209,19 +231,17 @@ void onEvent(ev_t ev) {
|
||||
|
||||
case EV_JOINED:
|
||||
strcpy_P(buff, PSTR("JOINED"));
|
||||
sprintf(display_line6, " "); // clear previous lmic status
|
||||
// set data rate adaptation according to saved setting
|
||||
LMIC_setAdrMode(cfg.adrmode);
|
||||
// set cyclic lmic link check to off if no ADR because is not supported by
|
||||
// ttn (but enabled by lmic after join)
|
||||
LMIC_setLinkCheckMode(cfg.adrmode);
|
||||
// Set data rate and transmit power (note: txpower seems to be ignored by
|
||||
// the library)
|
||||
switch_lora(cfg.lorasf, cfg.txpower);
|
||||
// kickoff first send job
|
||||
os_setCallback(&sendjob, lora_send);
|
||||
// show effective LoRa parameters after join
|
||||
// set data rate and transmit power to defaults only if we have no ADR
|
||||
if (!cfg.adrmode)
|
||||
LMIC_setDrTxpow(assertDR(cfg.loradr), cfg.txpower);
|
||||
// show current devaddr
|
||||
ESP_LOGI(TAG, "DEVaddr=%08X", LMIC.devaddr);
|
||||
ESP_LOGI(TAG, "Radio parameters %s / %s / %s",
|
||||
getSfName(updr2rps(LMIC.datarate)),
|
||||
getBwName(updr2rps(LMIC.datarate)),
|
||||
getCrName(updr2rps(LMIC.datarate)));
|
||||
break;
|
||||
|
||||
case EV_RFU1:
|
||||
@@ -237,46 +257,7 @@ void onEvent(ev_t ev) {
|
||||
break;
|
||||
|
||||
case EV_TXCOMPLETE:
|
||||
|
||||
#if (TIME_SYNC_LORASERVER)
|
||||
// if last packet sent was a timesync request, store TX timestamp
|
||||
if (LMIC.pendTxPort == TIMEPORT)
|
||||
store_time_sync_req(osticks2ms(LMIC.txend)); // milliseconds
|
||||
#endif
|
||||
|
||||
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK")
|
||||
: PSTR("TX COMPLETE"));
|
||||
sprintf(display_line6, " "); // clear previous lmic status
|
||||
|
||||
if (LMIC.dataLen) { // did we receive payload data -> display info
|
||||
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d",
|
||||
LMIC.dataLen, LMIC.rssi, LMIC.snr / 4);
|
||||
sprintf(display_line6, "RSSI %d SNR %d", LMIC.rssi, LMIC.snr / 4);
|
||||
|
||||
if (LMIC.txrxFlags & TXRX_PORT) { // FPort -> use to switch
|
||||
|
||||
switch (LMIC.frame[LMIC.dataBeg - 1]) {
|
||||
|
||||
case RCMDPORT: // opcode -> call rcommand interpreter
|
||||
rcommand(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
#if (TIME_SYNC_LORASERVER)
|
||||
// timesync answer -> call timesync processor
|
||||
if (LMIC.frame[LMIC.dataBeg - 1] == TIMEPORT) {
|
||||
recv_timesync_ans(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// unknown port -> display info
|
||||
ESP_LOGI(TAG, "Received data on unsupported port #%d",
|
||||
LMIC.frame[LMIC.dataBeg - 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
strcpy_P(buff, PSTR("TX COMPLETE"));
|
||||
break;
|
||||
|
||||
case EV_LOST_TSYNC:
|
||||
@@ -306,13 +287,7 @@ void onEvent(ev_t ev) {
|
||||
|
||||
case EV_TXSTART:
|
||||
if (!(LMIC.opmode & OP_JOINING)) {
|
||||
#if (TIME_SYNC_LORASERVER)
|
||||
// if last packet sent was a timesync request, store TX time
|
||||
if (LMIC.pendTxPort == TIMEPORT)
|
||||
strcpy_P(buff, PSTR("TX TIMESYNC"));
|
||||
else
|
||||
#endif
|
||||
strcpy_P(buff, PSTR("TX START"));
|
||||
strcpy_P(buff, PSTR("TX START"));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -336,80 +311,58 @@ void onEvent(ev_t ev) {
|
||||
// Log & Display if asked
|
||||
if (*buff) {
|
||||
ESP_LOGI(TAG, "%s", buff);
|
||||
sprintf(display_line7, buff);
|
||||
sprintf(lmic_event_msg, buff);
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to assign LoRa datarates to numeric spreadfactor values
|
||||
void switch_lora(uint8_t sf, uint8_t tx) {
|
||||
if (tx > 20)
|
||||
return;
|
||||
cfg.txpower = tx;
|
||||
switch (sf) {
|
||||
case 7:
|
||||
LMIC_setDrTxpow(DR_SF7, tx);
|
||||
cfg.lorasf = sf;
|
||||
break;
|
||||
case 8:
|
||||
LMIC_setDrTxpow(DR_SF8, tx);
|
||||
cfg.lorasf = sf;
|
||||
break;
|
||||
case 9:
|
||||
LMIC_setDrTxpow(DR_SF9, tx);
|
||||
cfg.lorasf = sf;
|
||||
break;
|
||||
case 10:
|
||||
LMIC_setDrTxpow(DR_SF10, tx);
|
||||
cfg.lorasf = sf;
|
||||
break;
|
||||
case 11:
|
||||
#if defined(CFG_us915)
|
||||
LMIC_setDrTxpow(DR_SF11CR, tx);
|
||||
cfg.lorasf = sf;
|
||||
break;
|
||||
#else
|
||||
LMIC_setDrTxpow(DR_SF11, tx);
|
||||
cfg.lorasf = sf;
|
||||
break;
|
||||
#endif
|
||||
case 12:
|
||||
#if defined(CFG_us915)
|
||||
LMIC_setDrTxpow(DR_SF12CR, tx);
|
||||
cfg.lorasf = sf;
|
||||
break;
|
||||
#else
|
||||
LMIC_setDrTxpow(DR_SF12, tx);
|
||||
cfg.lorasf = sf;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// LMIC send task
|
||||
void lora_send(void *pvParameters) {
|
||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||
|
||||
void lora_send(osjob_t *job) {
|
||||
MessageBuffer_t SendBuffer;
|
||||
// Check if there is a pending TX/RX job running, if yes don't eat data
|
||||
// since it cannot be sent right now
|
||||
if ((LMIC.opmode & (OP_JOINING | OP_REJOIN | OP_TXDATA | OP_POLL)) != 0) {
|
||||
// waiting for LoRa getting ready
|
||||
} else {
|
||||
if (xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) {
|
||||
// SendBuffer now filled with next payload from queue
|
||||
if (!LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message,
|
||||
SendBuffer.MessageSize, (cfg.countermode & 0x02))) {
|
||||
ESP_LOGI(TAG, "%d byte(s) sent to LoRa", SendBuffer.MessageSize);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "could not send %d byte(s) to LoRa",
|
||||
SendBuffer.MessageSize);
|
||||
}
|
||||
// sprintf(display_line7, "PACKET QUEUED");
|
||||
|
||||
while (1) {
|
||||
|
||||
// postpone until we are joined if we are not
|
||||
while (!LMIC.devaddr) {
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
}
|
||||
|
||||
// fetch next or wait for payload to send from queue
|
||||
if (xQueueReceive(LoraSendQueue, &SendBuffer, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// attempt to transmit payload
|
||||
else {
|
||||
|
||||
switch (LMIC_sendWithCallback_strict(
|
||||
SendBuffer.MessagePort, SendBuffer.Message, SendBuffer.MessageSize,
|
||||
(cfg.countermode & 0x02), myTxCallback, NULL)) {
|
||||
|
||||
case LMIC_ERROR_SUCCESS:
|
||||
ESP_LOGI(TAG, "%d byte(s) sent to LORA", SendBuffer.MessageSize);
|
||||
break;
|
||||
case LMIC_ERROR_TX_BUSY: // LMIC already has a tx message pending
|
||||
case LMIC_ERROR_TX_FAILED: // message was not sent
|
||||
// ESP_LOGD(TAG, "LMIC busy, message re-enqueued"); // very noisy
|
||||
vTaskDelay(pdMS_TO_TICKS(1000 + random(500))); // wait a while
|
||||
lora_enqueuedata(&SendBuffer); // re-enqueue the undelivered message
|
||||
break;
|
||||
case LMIC_ERROR_TX_TOO_LARGE: // message size exceeds LMIC buffer size
|
||||
case LMIC_ERROR_TX_NOT_FEASIBLE: // message too large for current datarate
|
||||
ESP_LOGI(TAG,
|
||||
"Message too large to send, message not sent and deleted");
|
||||
// we need some kind of error handling here -> to be done
|
||||
break;
|
||||
default: // other LMIC return code
|
||||
ESP_LOGE(TAG, "LMIC error, message not sent and deleted");
|
||||
|
||||
} // switch
|
||||
}
|
||||
delay(2); // yield to CPU
|
||||
}
|
||||
// reschedule job every 0,5 - 1 sec. including a bit of random to prevent
|
||||
// systematic collisions
|
||||
os_setTimedCallback(job, os_getTime() + 500 + ms2osticks(random(500)),
|
||||
lora_send);
|
||||
}
|
||||
|
||||
esp_err_t lora_stack_init() {
|
||||
@@ -422,13 +375,13 @@ esp_err_t lora_stack_init() {
|
||||
ESP_LOGI(TAG, "LORA send queue created, size %d Bytes",
|
||||
SEND_QUEUE_SIZE * sizeof(MessageBuffer_t));
|
||||
|
||||
// starting lorawan stack
|
||||
// start lorawan stack
|
||||
ESP_LOGI(TAG, "Starting LMIC...");
|
||||
xTaskCreatePinnedToCore(lmictask, // task function
|
||||
"lmictask", // name of task
|
||||
4096, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
2, // priority of the task
|
||||
5, // priority of the task
|
||||
&lmicTask, // task handle
|
||||
1); // CPU core
|
||||
|
||||
@@ -436,18 +389,31 @@ esp_err_t lora_stack_init() {
|
||||
ESP_LOGI(TAG, "Already joined");
|
||||
}
|
||||
|
||||
return ESP_OK; // continue main program
|
||||
// start lmic send task
|
||||
xTaskCreatePinnedToCore(lora_send, // task function
|
||||
"lorasendtask", // name of task
|
||||
3072, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
1, // priority of the task
|
||||
&lorasendTask, // task handle
|
||||
1); // CPU core
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void lora_enqueuedata(MessageBuffer_t *message, sendprio_t prio) {
|
||||
void lora_enqueuedata(MessageBuffer_t *message) {
|
||||
// enqueue message in LORA send queue
|
||||
BaseType_t ret;
|
||||
BaseType_t ret = pdFALSE;
|
||||
MessageBuffer_t DummyBuffer;
|
||||
sendprio_t prio = message->MessagePrio;
|
||||
|
||||
switch (prio) {
|
||||
case prio_high:
|
||||
// clear space in queue if full, then fallthrough to normal
|
||||
if (uxQueueSpacesAvailable(LoraSendQueue) == 0)
|
||||
// clear some space in queue if full, then fallthrough to prio_normal
|
||||
if (uxQueueSpacesAvailable(LoraSendQueue) == 0) {
|
||||
xQueueReceive(LoraSendQueue, &DummyBuffer, (TickType_t)0);
|
||||
ESP_LOGW(TAG, "LORA sendqueue purged, data is lost");
|
||||
}
|
||||
case prio_normal:
|
||||
ret = xQueueSendToFront(LoraSendQueue, (void *)message, (TickType_t)0);
|
||||
break;
|
||||
@@ -519,17 +485,17 @@ void lmictask(void *pvParameters) {
|
||||
os_init(); // initialize lmic run-time environment
|
||||
LMIC_reset(); // initialize lmic MAC
|
||||
LMIC_setLinkCheckMode(0);
|
||||
// This tells LMIC to make the receive windows bigger, in case your clock is
|
||||
// faster or slower. This causes the transceiver to be earlier switched on,
|
||||
// so consuming more power. You may sharpen (reduce) CLOCK_ERROR_PERCENTAGE
|
||||
// in src/lmic_config.h if you are limited on battery.
|
||||
LMIC_setClockError(MAX_CLOCK_ERROR * CLOCK_ERROR_PROCENTAGE / 100);
|
||||
// Set the data rate to Spreading Factor 7. This is the fastest supported
|
||||
// rate for 125 kHz channels, and it minimizes air time and battery power.
|
||||
// Set the transmission power to 14 dBi (25 mW).
|
||||
LMIC_setDrTxpow(DR_SF7, 14);
|
||||
|
||||
#if defined(CFG_US915) || defined(CFG_au921)
|
||||
// This tells LMIC to make the receive windows bigger, in case your clock is
|
||||
// faster or slower. This causes the transceiver to be earlier switched on,
|
||||
// so consuming more power. You may sharpen (reduce) CLOCK_ERROR_PERCENTAGE
|
||||
// in src/lmic_config.h if you are limited on battery.
|
||||
#ifdef CLOCK_ERROR_PROCENTAGE
|
||||
LMIC_setClockError(MAX_CLOCK_ERROR * CLOCK_ERROR_PROCENTAGE / 100);
|
||||
#endif
|
||||
|
||||
//#if defined(CFG_US915) || defined(CFG_au921)
|
||||
#if CFG_LMIC_US_like
|
||||
// in the US, with TTN, it saves join time if we start on subband 1
|
||||
// (channels 8-15). This will get overridden after the join by parameters
|
||||
// from the network. If working with other networks or in other regions,
|
||||
@@ -537,10 +503,161 @@ void lmictask(void *pvParameters) {
|
||||
LMIC_selectSubBand(1);
|
||||
#endif
|
||||
|
||||
// Set the data rate to Spreading Factor 7. This is the fastest supported
|
||||
// rate for 125 kHz channels, and it minimizes air time and battery power.
|
||||
// Set the transmission power to 14 dBi (25 mW).
|
||||
LMIC_setDrTxpow(DR_SF7, 14);
|
||||
|
||||
// register a callback for downlink messages. We aren't trying to write
|
||||
// reentrant code, so pUserData is NULL.
|
||||
LMIC_registerRxMessageCb(myRxCallback, NULL);
|
||||
|
||||
while (1) {
|
||||
os_runloop_once(); // execute lmic scheduled jobs and events
|
||||
delay(2); // yield to CPU
|
||||
}
|
||||
} // lmictask
|
||||
|
||||
// receive message handler
|
||||
void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
|
||||
size_t nMsg) {
|
||||
|
||||
// display type of received data
|
||||
if (nMsg)
|
||||
ESP_LOGI(TAG, "Received %u byte(s) of payload on port %u", nMsg, port);
|
||||
else if (port)
|
||||
ESP_LOGI(TAG, "Received empty message on port %u", port);
|
||||
|
||||
// list MAC messages, if any
|
||||
uint8_t nMac = pMsg - &LMIC.frame[0];
|
||||
if (port != MACPORT)
|
||||
--nMac;
|
||||
if (nMac) {
|
||||
ESP_LOGI(TAG, "%u byte(s) downlink MAC commands", nMac);
|
||||
// NOT WORKING YET
|
||||
// whe need to unwrap the MAC command from LMIC.frame here
|
||||
// mac_decode(LMIC.frame, nMac, MACdn_table, sizeof(MACdn_table) /
|
||||
// sizeof(MACdn_table[0]));
|
||||
}
|
||||
|
||||
if (LMIC.pendMacLen) {
|
||||
ESP_LOGI(TAG, "%u byte(s) uplink MAC commands", LMIC.pendMacLen);
|
||||
mac_decode(LMIC.pendMacData, LMIC.pendMacLen, MACup_table,
|
||||
sizeof(MACup_table) / sizeof(MACup_table[0]));
|
||||
}
|
||||
|
||||
switch (port) {
|
||||
|
||||
// ignore mac messages
|
||||
case MACPORT:
|
||||
break;
|
||||
|
||||
// rcommand received -> call interpreter
|
||||
case RCMDPORT:
|
||||
rcommand(pMsg, nMsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
#if (TIME_SYNC_LORASERVER)
|
||||
// valid timesync answer -> call timesync processor
|
||||
if ((port >= TIMEANSWERPORT_MIN) && (port <= TIMEANSWERPORT_MAX)) {
|
||||
recv_timesync_ans(port, pMsg, nMsg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
// unknown port -> display info
|
||||
ESP_LOGI(TAG, "Received data on unsupported port %u", port);
|
||||
break;
|
||||
} // switch
|
||||
}
|
||||
|
||||
// transmit complete message handler
|
||||
void myTxCallback(void *pUserData, int fSuccess) {
|
||||
|
||||
#if (TIME_SYNC_LORASERVER)
|
||||
// if last packet sent was a timesync request, store TX timestamp
|
||||
if (LMIC.pendTxPort == TIMEPORT)
|
||||
store_time_sync_req(osticks2ms(LMIC.txend)); // milliseconds
|
||||
#endif
|
||||
}
|
||||
|
||||
// decode LORAWAN MAC message
|
||||
void mac_decode(const uint8_t cmd[], const uint8_t cmdlen, const mac_t table[],
|
||||
const uint8_t tablesize) {
|
||||
|
||||
if (!cmdlen)
|
||||
return;
|
||||
|
||||
uint8_t foundcmd[cmdlen], cursor = 0;
|
||||
|
||||
while (cursor < cmdlen) {
|
||||
|
||||
int i = tablesize; // number of commands in table
|
||||
|
||||
while (i--) {
|
||||
if (cmd[cursor] == table[i].opcode) { // lookup command in opcode table
|
||||
cursor++; // strip 1 byte opcode
|
||||
if ((cursor + table[i].params) <= cmdlen) {
|
||||
memmove(foundcmd, cmd + cursor,
|
||||
table[i].params); // strip opcode from cmd array
|
||||
cursor += table[i].params;
|
||||
ESP_LOGD(TAG, "MAC command %s", table[i].cmdname);
|
||||
} else
|
||||
ESP_LOGD(TAG, "MAC command 0x%02X with missing parameter(s)",
|
||||
table[i].opcode);
|
||||
break; // command found -> exit table lookup loop
|
||||
} // end of command validation
|
||||
} // end of command table lookup loop
|
||||
if (i < 0) { // command not found -> skip it
|
||||
ESP_LOGD(TAG, "Unknown MAC command 0x%02X", cmd[cursor]);
|
||||
cursor++;
|
||||
}
|
||||
} // command parsing loop
|
||||
|
||||
} // mac_decode()
|
||||
|
||||
uint8_t getBattLevel() {
|
||||
/*
|
||||
return values:
|
||||
MCMD_DEVS_EXT_POWER = 0x00, // external power supply
|
||||
MCMD_DEVS_BATT_MIN = 0x01, // min battery value
|
||||
MCMD_DEVS_BATT_MAX = 0xFE, // max battery value
|
||||
MCMD_DEVS_BATT_NOINFO = 0xFF, // unknown battery level
|
||||
*/
|
||||
#if (defined HAS_PMU || defined BAT_MEASURE_ADC)
|
||||
uint16_t voltage = read_voltage();
|
||||
|
||||
switch (voltage) {
|
||||
case 0:
|
||||
return MCMD_DEVS_BATT_NOINFO;
|
||||
case 0xffff:
|
||||
return MCMD_DEVS_EXT_POWER;
|
||||
default:
|
||||
return (voltage > OTA_MIN_BATT ? MCMD_DEVS_BATT_MAX : MCMD_DEVS_BATT_MIN);
|
||||
}
|
||||
#else // we don't have any info on battery level
|
||||
return MCMD_DEVS_BATT_NOINFO;
|
||||
#endif
|
||||
} // getBattLevel()
|
||||
|
||||
// u1_t os_getBattLevel(void) { return getBattLevel(); };
|
||||
|
||||
const char *getSfName(rps_t rps) {
|
||||
const char *const t[] = {"FSK", "SF7", "SF8", "SF9",
|
||||
"SF10", "SF11", "SF12", "SF?"};
|
||||
return t[getSf(rps)];
|
||||
}
|
||||
|
||||
const char *getBwName(rps_t rps) {
|
||||
const char *const t[] = {"BW125", "BW250", "BW500", "BW?"};
|
||||
return t[getBw(rps)];
|
||||
}
|
||||
|
||||
const char *getCrName(rps_t rps) {
|
||||
const char *const t[] = {"CR 4/5", "CR 4/6", "CR 4/7", "CR 4/8"};
|
||||
return t[getCr(rps)];
|
||||
}
|
||||
|
||||
#endif // HAS_LORA
|
||||
+47
-33
@@ -31,12 +31,12 @@ ledloop 0 3 blinks LEDs
|
||||
spiloop 0 2 reads/writes data on spi interface
|
||||
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
|
||||
|
||||
lmictask 1 5 MCCI LMiC LORAWAN stack
|
||||
clockloop 1 4 generates realtime telegrams for external clock
|
||||
timesync_req 1 3 processes realtime time sync requests
|
||||
lmictask 1 2 MCCI LMiC LORAWAN stack
|
||||
irqhandler 1 1 display, timesync, gps, etc. triggered by timers
|
||||
gpsloop 1 1 reads data from GPS via serial or i2c
|
||||
looptask 1 1 arduino loop (unused)
|
||||
lorasendtask 1 1 feed data from lora sendqueue to lmcic
|
||||
IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator
|
||||
|
||||
Low priority numbers denote low priority tasks.
|
||||
@@ -58,6 +58,7 @@ fired by hardware
|
||||
DisplayIRQ -> esp32 timer 0 -> irqHandlerTask (Core 1)
|
||||
CLOCKIRQ -> esp32 timer 1 -> ClockTask (Core 1)
|
||||
ButtonIRQ -> external gpio -> irqHandlerTask (Core 1)
|
||||
PMUIRQ -> PMU chip gpio -> irqHandlerTask (Core 1)
|
||||
|
||||
fired by software (Ticker.h)
|
||||
TIMESYNC_IRQ -> timeSync() -> irqHandlerTask (Core 1)
|
||||
@@ -75,9 +76,9 @@ triggers pps 1 sec impulse
|
||||
// Basic Config
|
||||
#include "main.h"
|
||||
|
||||
configData_t cfg; // struct holds current device configuration
|
||||
char display_line6[16], display_line7[16]; // display buffers
|
||||
uint8_t volatile channel = 0; // channel rotation counter
|
||||
configData_t cfg; // struct holds current device configuration
|
||||
char lmic_event_msg[16]; // display buffer for LMIC event message
|
||||
uint8_t volatile channel = 0; // channel rotation counter
|
||||
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
||||
batt_voltage = 0; // globals for display
|
||||
|
||||
@@ -169,24 +170,45 @@ void setup() {
|
||||
ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion());
|
||||
#endif
|
||||
|
||||
// open i2c bus
|
||||
#ifdef HAS_DISPLAY
|
||||
Wire.begin(MY_OLED_SDA, MY_OLED_SCL, 100000);
|
||||
#else
|
||||
Wire.begin(SDA, SCL, 100000);
|
||||
#endif
|
||||
|
||||
// setup power on boards with power management logic
|
||||
#ifdef EXT_POWER_SW
|
||||
pinMode(EXT_POWER_SW, OUTPUT);
|
||||
digitalWrite(EXT_POWER_SW, EXT_POWER_ON);
|
||||
strcat_P(features, " VEXT");
|
||||
#endif
|
||||
#ifdef HAS_PMU
|
||||
AXP192_init();
|
||||
strcat_P(features, " PMU");
|
||||
#endif
|
||||
|
||||
// scan i2c bus for devices
|
||||
i2c_scan();
|
||||
|
||||
#endif // verbose
|
||||
|
||||
// read (and initialize on first run) runtime settings from NVRAM
|
||||
loadConfig(); // includes initialize if necessary
|
||||
|
||||
// initialize display
|
||||
#ifdef HAS_DISPLAY
|
||||
strcat_P(features, " OLED");
|
||||
DisplayIsOn = cfg.screenon;
|
||||
init_display(PRODUCTNAME, PROGVERSION); // note: blocking call
|
||||
#endif
|
||||
|
||||
#ifdef BOARD_HAS_PSRAM
|
||||
assert(psramFound());
|
||||
ESP_LOGI(TAG, "PSRAM found and initialized");
|
||||
strcat_P(features, " PSRAM");
|
||||
#endif
|
||||
|
||||
// set external power mode
|
||||
#ifdef EXT_POWER_SW
|
||||
pinMode(EXT_POWER_SW, OUTPUT);
|
||||
digitalWrite(EXT_POWER_SW, EXT_POWER_ON);
|
||||
strcat_P(features, " VEXT");
|
||||
#endif
|
||||
|
||||
#ifdef BAT_MEASURE_EN
|
||||
pinMode(BAT_MEASURE_EN, OUTPUT);
|
||||
#endif
|
||||
@@ -195,17 +217,25 @@ void setup() {
|
||||
#if (HAS_LED != NOT_A_PIN)
|
||||
pinMode(HAS_LED, OUTPUT);
|
||||
strcat_P(features, " LED");
|
||||
|
||||
#ifdef LED_POWER_SW
|
||||
pinMode(LED_POWER_SW, OUTPUT);
|
||||
digitalWrite(LED_POWER_SW, LED_POWER_ON);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_TWO_LED
|
||||
pinMode(HAS_TWO_LED, OUTPUT);
|
||||
strcat_P(features, " LED1");
|
||||
#endif
|
||||
|
||||
// use LED for power display if we have additional RGB LED, else for status
|
||||
#ifdef HAS_RGB_LED
|
||||
switch_LED(LED_ON);
|
||||
strcat_P(features, " RGB");
|
||||
rgb_set_color(COLOR_PINK);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // HAS_LED
|
||||
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
// start led loop
|
||||
@@ -227,7 +257,7 @@ void setup() {
|
||||
#endif
|
||||
|
||||
// initialize battery status
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
#if (defined BAT_MEASURE_ADC || defined HAS_PMU)
|
||||
strcat_P(features, " BATT");
|
||||
calibrate_voltage();
|
||||
batt_voltage = read_voltage();
|
||||
@@ -297,13 +327,6 @@ void setup() {
|
||||
strcat_P(features, " FILTER");
|
||||
#endif
|
||||
|
||||
// initialize display
|
||||
#ifdef HAS_DISPLAY
|
||||
strcat_P(features, " OLED");
|
||||
DisplayIsOn = cfg.screenon;
|
||||
init_display(PRODUCTNAME, PROGVERSION); // note: blocking call
|
||||
#endif
|
||||
|
||||
// initialize matrix display
|
||||
#ifdef HAS_MATRIX_DISPLAY
|
||||
strcat_P(features, " LED_MATRIX");
|
||||
@@ -419,12 +442,10 @@ void setup() {
|
||||
#warning you did not specify a time source, time will not be synched
|
||||
#endif
|
||||
|
||||
/*
|
||||
// initialize gps time
|
||||
#if (HAS_GPS)
|
||||
fetch_gpsTime();
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if (defined HAS_IF482 || defined HAS_DCF77)
|
||||
ESP_LOGI(TAG, "Starting Clock Controller...");
|
||||
@@ -445,18 +466,11 @@ void setup() {
|
||||
ESP_LOGI(TAG, "Features:%s", features);
|
||||
|
||||
macsniff_setup();
|
||||
|
||||
|
||||
uart_setup();
|
||||
|
||||
} // setup()
|
||||
|
||||
void loop() {
|
||||
} // setup()
|
||||
|
||||
while (1) {
|
||||
#if (HAS_LORA)
|
||||
os_runloop_once(); // execute lmic scheduled jobs and events
|
||||
#else
|
||||
delay(2); // yield to CPU
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void loop() { vTaskDelete(NULL); }
|
||||
+7
-3
@@ -1,3 +1,5 @@
|
||||
// clang-format off
|
||||
|
||||
// ----- Paxcounter user config file ------
|
||||
//
|
||||
// --> adapt to your needs and use case <--
|
||||
@@ -46,7 +48,8 @@
|
||||
#define MEM_LOW 2048 // [Bytes] low memory threshold triggering a send cycle
|
||||
#define RETRANSMIT_RCMD 5 // [seconds] wait time before retransmitting rcommand results
|
||||
#define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit
|
||||
#define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs
|
||||
#define LORADRDEFAULT 5 // 0 .. 15, LoRaWAN datarate, according to regional LoRaWAN specs [default = 5]
|
||||
#define LORATXPOWDEFAULT 7 // 0 .. 255, LoRaWAN TX power in dBm [default = 14]
|
||||
#define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy
|
||||
#define SEND_QUEUE_SIZE 10 // maximum number of messages in payload send queue [1 = no queue]
|
||||
|
||||
@@ -72,7 +75,7 @@
|
||||
#define TIME_SYNC_INTERVAL_RETRY 10 // retry time sync after lost sync each .. minutes [default = 10], 0 means off
|
||||
#define TIME_SYNC_COMPILEDATE 0 // set to 1 to use compile date to initialize RTC after power outage [default = 0]
|
||||
#define TIME_SYNC_LORAWAN 0 // set to 1 to use LORA network as time source, 0 means off [default = 0]
|
||||
#define TIME_SYNC_LORASERVER 1 // set to 1 to use LORA timeserver as time source, 0 means off [default = 0]
|
||||
#define TIME_SYNC_LORASERVER 0 // set to 1 to use LORA timeserver as time source, 0 means off [default = 0]
|
||||
|
||||
// settings for syncing time with timeserver applications
|
||||
#define TIME_SYNC_SAMPLES 1 // number of time requests for averaging
|
||||
@@ -85,6 +88,7 @@
|
||||
|
||||
// Ports on which the device sends and listenes on LoRaWAN and SPI
|
||||
#define COUNTERPORT 1 // counts
|
||||
#define MACPORT 0 // network commands
|
||||
#define RCMDPORT 2 // remote commands
|
||||
#define STATUSPORT 2 // remote command results
|
||||
#define CONFIGPORT 3 // config query results
|
||||
@@ -107,4 +111,4 @@
|
||||
#define CAYENNE_ACTUATOR 10 // actuator commands
|
||||
#define CAYENNE_DEVICECONFIG 11 // device period configuration
|
||||
#define CAYENNE_SENSORREAD 13 // sensor period configuration
|
||||
#define CAYENNE_SENSORENABLE 14 // sensor enable configuration
|
||||
#define CAYENNE_SENSORENABLE 14 // sensor enable configuration
|
||||
+3
-3
@@ -43,7 +43,7 @@ void PayloadConvert::addVoltage(uint16_t value) {
|
||||
}
|
||||
|
||||
void PayloadConvert::addConfig(configData_t value) {
|
||||
buffer[cursor++] = value.lorasf;
|
||||
buffer[cursor++] = value.loradr;
|
||||
buffer[cursor++] = value.txpower;
|
||||
buffer[cursor++] = value.adrmode;
|
||||
buffer[cursor++] = value.screensaver;
|
||||
@@ -164,7 +164,7 @@ void PayloadConvert::addAlarm(int8_t rssi, uint8_t msg) {
|
||||
void PayloadConvert::addVoltage(uint16_t value) { writeUint16(value); }
|
||||
|
||||
void PayloadConvert::addConfig(configData_t value) {
|
||||
writeUint8(value.lorasf);
|
||||
writeUint8(value.loradr);
|
||||
writeUint8(value.txpower);
|
||||
writeUint16(value.rssilimit);
|
||||
writeUint8(value.sendcycle);
|
||||
@@ -378,7 +378,7 @@ void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float celsius,
|
||||
uint32_t mem, uint8_t reset1, uint8_t reset2) {
|
||||
uint16_t temp = celsius * 10;
|
||||
uint16_t volt = voltage / 10;
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
#if (defined BAT_MEASURE_ADC || defined HAS_PMU)
|
||||
#if (PAYLOAD_ENCODER == 3)
|
||||
buffer[cursor++] = LPP_BATT_CHANNEL;
|
||||
#endif
|
||||
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
// Basic config
|
||||
#include "globals.h"
|
||||
#include "power.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
#ifdef HAS_PMU
|
||||
|
||||
AXP20X_Class pmu;
|
||||
|
||||
void power_event_IRQ(void) {
|
||||
|
||||
if (!I2C_MUTEX_LOCK())
|
||||
ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0);
|
||||
else {
|
||||
|
||||
pmu.readIRQ();
|
||||
// put your power event handler code here
|
||||
|
||||
if (pmu.isVbusOverVoltageIRQ())
|
||||
ESP_LOGI(TAG, "USB voltage %.2fV too high.", pmu.getVbusVoltage() / 1000);
|
||||
if (pmu.isVbusPlugInIRQ())
|
||||
ESP_LOGI(TAG, "USB plugged, %.2fV @ %.0mA", pmu.getVbusVoltage() / 1000,
|
||||
pmu.getVbusCurrent());
|
||||
if (pmu.isVbusRemoveIRQ())
|
||||
ESP_LOGI(TAG, "USB unplugged.");
|
||||
|
||||
if (pmu.isBattPlugInIRQ())
|
||||
ESP_LOGI(TAG, "Battery is connected.");
|
||||
if (pmu.isBattRemoveIRQ())
|
||||
ESP_LOGI(TAG, "Battery was removed.");
|
||||
if (pmu.isChargingIRQ())
|
||||
ESP_LOGI(TAG, "Battery charging.");
|
||||
if (pmu.isChargingDoneIRQ())
|
||||
ESP_LOGI(TAG, "Battery charging done.");
|
||||
if (pmu.isBattTempLowIRQ())
|
||||
ESP_LOGI(TAG, "Battery high temperature.");
|
||||
if (pmu.isBattTempHighIRQ())
|
||||
ESP_LOGI(TAG, "Battery low temperature.");
|
||||
|
||||
// display on/off
|
||||
if (pmu.isPEKShortPressIRQ()) {
|
||||
cfg.screenon = !cfg.screenon;
|
||||
}
|
||||
|
||||
// shutdown power
|
||||
if (pmu.isPEKLongtPressIRQ()) {
|
||||
AXP192_power(false); // switch off Lora, GPS, display
|
||||
pmu.shutdown();
|
||||
}
|
||||
|
||||
pmu.clearIRQ();
|
||||
I2C_MUTEX_UNLOCK();
|
||||
} // mutex
|
||||
|
||||
// refresh stored voltage value
|
||||
read_voltage();
|
||||
}
|
||||
|
||||
void AXP192_power(bool on) {
|
||||
if (on) {
|
||||
pmu.setPowerOutPut(AXP192_LDO2, AXP202_ON); // Lora on T-Beam V1.0
|
||||
pmu.setPowerOutPut(AXP192_LDO3, AXP202_ON); // Gps on T-Beam V1.0
|
||||
pmu.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED on T-Beam v1.0
|
||||
// pmu.setChgLEDMode(AXP20X_LED_LOW_LEVEL);
|
||||
pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ);
|
||||
} else {
|
||||
pmu.setChgLEDMode(AXP20X_LED_OFF);
|
||||
pmu.setPowerOutPut(AXP192_DCDC1, AXP202_OFF);
|
||||
pmu.setPowerOutPut(AXP192_LDO3, AXP202_OFF);
|
||||
pmu.setPowerOutPut(AXP192_LDO2, AXP202_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
void AXP192_showstatus(void) {
|
||||
|
||||
if (!I2C_MUTEX_LOCK())
|
||||
ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0);
|
||||
else {
|
||||
|
||||
if (pmu.isBatteryConnect())
|
||||
if (pmu.isChargeing())
|
||||
ESP_LOGI(TAG, "Battery charging, %.2fV @ %.0fmAh",
|
||||
pmu.getBattVoltage() / 1000, pmu.getBattChargeCurrent());
|
||||
else
|
||||
ESP_LOGI(TAG, "Battery not charging");
|
||||
else
|
||||
ESP_LOGI(TAG, "No Battery");
|
||||
|
||||
if (pmu.isVBUSPlug())
|
||||
ESP_LOGI(TAG, "USB powered, %.0fmW",
|
||||
pmu.getVbusVoltage() / 1000 * pmu.getVbusCurrent());
|
||||
else
|
||||
ESP_LOGI(TAG, "USB not present");
|
||||
|
||||
I2C_MUTEX_UNLOCK();
|
||||
} // mutex
|
||||
}
|
||||
|
||||
void AXP192_init(void) {
|
||||
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
|
||||
if (pmu.begin(Wire, AXP192_PRIMARY_ADDRESS))
|
||||
ESP_LOGI(TAG, "AXP192 PMU initialization failed");
|
||||
else {
|
||||
|
||||
// configure AXP192
|
||||
pmu.setDCDC1Voltage(3300); // for external OLED display
|
||||
pmu.setTimeOutShutdown(false); // no automatic shutdown
|
||||
pmu.setTSmode(AXP_TS_PIN_MODE_DISABLE); // TS pin mode off to save power
|
||||
|
||||
// switch ADCs on
|
||||
pmu.adc1Enable(AXP202_BATT_VOL_ADC1, true);
|
||||
pmu.adc1Enable(AXP202_BATT_CUR_ADC1, true);
|
||||
pmu.adc1Enable(AXP202_VBUS_VOL_ADC1, true);
|
||||
pmu.adc1Enable(AXP202_VBUS_CUR_ADC1, true);
|
||||
|
||||
// switch power rails on
|
||||
AXP192_power(true);
|
||||
|
||||
// I2C access of AXP202X library currently is not mutexable
|
||||
// so we better should disable AXP interrupts... ?
|
||||
#ifdef PMU_INT
|
||||
pinMode(PMU_INT, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(PMU_INT), PMUIRQ, FALLING);
|
||||
pmu.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ |
|
||||
AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ |
|
||||
AXP202_CHARGING_FINISHED_IRQ,
|
||||
1);
|
||||
pmu.clearIRQ();
|
||||
#endif // PMU_INT
|
||||
|
||||
ESP_LOGI(TAG, "AXP192 PMU initialized");
|
||||
}
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
} else
|
||||
ESP_LOGE(TAG, "I2c bus busy - PMU initialization error");
|
||||
}
|
||||
#endif // HAS_PMU
|
||||
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
esp_adc_cal_characteristics_t *adc_characs =
|
||||
(esp_adc_cal_characteristics_t *)calloc(
|
||||
1, sizeof(esp_adc_cal_characteristics_t));
|
||||
|
||||
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
||||
static const adc1_channel_t adc_channel = BAT_MEASURE_ADC;
|
||||
#else // ADC2
|
||||
static const adc2_channel_t adc_channel = BAT_MEASURE_ADC;
|
||||
#endif
|
||||
static const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||
static const adc_unit_t unit = ADC_UNIT_1;
|
||||
|
||||
#endif // BAT_MEASURE_ADC
|
||||
|
||||
void calibrate_voltage(void) {
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
// configure ADC
|
||||
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
||||
ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12));
|
||||
ESP_ERROR_CHECK(adc1_config_channel_atten(adc_channel, atten));
|
||||
#else // ADC2
|
||||
// ESP_ERROR_CHECK(adc2_config_width(ADC_WIDTH_BIT_12));
|
||||
ESP_ERROR_CHECK(adc2_config_channel_atten(adc_channel, atten));
|
||||
#endif
|
||||
// calibrate ADC
|
||||
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(
|
||||
unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_characs);
|
||||
// show ADC characterization base
|
||||
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||
ESP_LOGI(TAG,
|
||||
"ADC characterization based on Two Point values stored in eFuse");
|
||||
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||
ESP_LOGI(TAG,
|
||||
"ADC characterization based on reference voltage stored in eFuse");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "ADC characterization based on default reference voltage");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool batt_sufficient() {
|
||||
#if (defined HAS_PMU || defined BAT_MEASURE_ADC)
|
||||
uint16_t volts = read_voltage();
|
||||
return ((volts < 1000) ||
|
||||
(volts > OTA_MIN_BATT)); // no battery or battery sufficient
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t read_voltage() {
|
||||
uint16_t voltage = 0;
|
||||
|
||||
#ifdef HAS_PMU
|
||||
if (!I2C_MUTEX_LOCK())
|
||||
ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0);
|
||||
else {
|
||||
voltage = pmu.isVBUSPlug() ? 0xffff : pmu.getBattVoltage();
|
||||
I2C_MUTEX_UNLOCK();
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
// multisample ADC
|
||||
uint32_t adc_reading = 0;
|
||||
int adc_buf = 0;
|
||||
for (int i = 0; i < NO_OF_SAMPLES; i++) {
|
||||
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
||||
adc_reading += adc1_get_raw(adc_channel);
|
||||
#else // ADC2
|
||||
ESP_ERROR_CHECK(adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf));
|
||||
adc_reading += adc_buf;
|
||||
#endif
|
||||
}
|
||||
adc_reading /= NO_OF_SAMPLES;
|
||||
// Convert ADC reading to voltage in mV
|
||||
voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_characs);
|
||||
#endif // BAT_MEASURE_ADC
|
||||
|
||||
#ifdef BAT_VOLTAGE_DIVIDER
|
||||
voltage *= BAT_VOLTAGE_DIVIDER;
|
||||
#endif // BAT_VOLTAGE_DIVIDER
|
||||
|
||||
#endif // HAS_PMU
|
||||
|
||||
return voltage;
|
||||
}
|
||||
+72
-26
@@ -19,32 +19,25 @@ void do_reset() {
|
||||
void set_reset(uint8_t val[]) {
|
||||
switch (val[0]) {
|
||||
case 0: // restart device
|
||||
sprintf(display_line6, "Reset pending");
|
||||
do_reset();
|
||||
break;
|
||||
case 1: // reset MAC counter
|
||||
ESP_LOGI(TAG, "Remote command: reset MAC counter");
|
||||
reset_counters(); // clear macs
|
||||
get_salt(); // get new salt
|
||||
sprintf(display_line6, "Reset counter");
|
||||
break;
|
||||
case 2: // reset device to factory settings
|
||||
ESP_LOGI(TAG, "Remote command: reset device to factory settings");
|
||||
sprintf(display_line6, "Factory reset");
|
||||
eraseConfig();
|
||||
break;
|
||||
case 3: // reset send queues
|
||||
ESP_LOGI(TAG, "Remote command: flush send queue");
|
||||
sprintf(display_line6, "Queue reset");
|
||||
flushQueues();
|
||||
break;
|
||||
case 9: // reset and ask for software update via Wifi OTA
|
||||
ESP_LOGI(TAG, "Remote command: software update via Wifi");
|
||||
#if (USE_OTA)
|
||||
sprintf(display_line6, "Software update");
|
||||
cfg.runmode = 1;
|
||||
#else
|
||||
sprintf(display_line6, "Software update not implemented");
|
||||
#endif // USE_OTA
|
||||
break;
|
||||
|
||||
@@ -127,10 +120,34 @@ void set_gps(uint8_t val[]) {
|
||||
if (val[0]) {
|
||||
cfg.payloadmask |= (uint8_t)GPS_DATA; // set bit in mask
|
||||
} else {
|
||||
cfg.payloadmask &= ~(uint8_t)GPS_DATA; // clear bit in mask
|
||||
cfg.payloadmask &= (uint8_t)~GPS_DATA; // clear bit in mask
|
||||
}
|
||||
}
|
||||
|
||||
void set_bme(uint8_t val[]) {
|
||||
ESP_LOGI(TAG, "Remote command: set BME mode to %s", val[0] ? "on" : "off");
|
||||
if (val[0]) {
|
||||
cfg.payloadmask |= (uint8_t)MEMS_DATA; // set bit in mask
|
||||
} else {
|
||||
cfg.payloadmask &= (uint8_t)~MEMS_DATA; // clear bit in mask
|
||||
}
|
||||
}
|
||||
|
||||
void set_batt(uint8_t val[]) {
|
||||
ESP_LOGI(TAG, "Remote command: set battery mode to %s",
|
||||
val[0] ? "on" : "off");
|
||||
if (val[0]) {
|
||||
cfg.payloadmask |= (uint8_t)BATT_DATA; // set bit in mask
|
||||
} else {
|
||||
cfg.payloadmask &= (uint8_t)~BATT_DATA; // clear bit in mask
|
||||
}
|
||||
}
|
||||
|
||||
void set_payloadmask(uint8_t val[]) {
|
||||
ESP_LOGI(TAG, "Remote command: set payload mask to %X", val[0]);
|
||||
cfg.payloadmask = val[0];
|
||||
}
|
||||
|
||||
void set_sensor(uint8_t val[]) {
|
||||
#if (HAS_SENSORS)
|
||||
switch (val[0]) { // check if valid sensor number 1...4
|
||||
@@ -169,10 +186,22 @@ void set_monitor(uint8_t val[]) {
|
||||
cfg.monitormode = val[0] ? 1 : 0;
|
||||
}
|
||||
|
||||
void set_lorasf(uint8_t val[]) {
|
||||
void set_loradr(uint8_t val[]) {
|
||||
#if (HAS_LORA)
|
||||
ESP_LOGI(TAG, "Remote command: set LoRa SF to %d", val[0]);
|
||||
switch_lora(val[0], cfg.txpower);
|
||||
if (validDR(val[0])) {
|
||||
cfg.loradr = val[0];
|
||||
ESP_LOGI(TAG, "Remote command: set LoRa Datarate to %d", cfg.loradr);
|
||||
LMIC_setDrTxpow(assertDR(cfg.loradr), cfg.txpower);
|
||||
ESP_LOGI(TAG, "Radio parameters now %s / %s / %s",
|
||||
getSfName(updr2rps(LMIC.datarate)),
|
||||
getBwName(updr2rps(LMIC.datarate)),
|
||||
getCrName(updr2rps(LMIC.datarate)));
|
||||
|
||||
} else
|
||||
ESP_LOGI(
|
||||
TAG,
|
||||
"Remote command: set LoRa Datarate called with illegal datarate %d",
|
||||
val[0]);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Remote command: LoRa not implemented");
|
||||
#endif // HAS_LORA
|
||||
@@ -223,8 +252,16 @@ void set_rgblum(uint8_t val[]) {
|
||||
|
||||
void set_lorapower(uint8_t val[]) {
|
||||
#if (HAS_LORA)
|
||||
ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %d", val[0]);
|
||||
switch_lora(cfg.lorasf, val[0]);
|
||||
// set data rate and transmit power only if we have no ADR
|
||||
if (!cfg.adrmode) {
|
||||
cfg.txpower = val[0];
|
||||
ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %d", cfg.txpower);
|
||||
LMIC_setDrTxpow(assertDR(cfg.loradr), cfg.txpower);
|
||||
} else
|
||||
ESP_LOGI(
|
||||
TAG,
|
||||
"Remote command: set LoRa TXPOWER, not executed because ADR is on");
|
||||
|
||||
#else
|
||||
ESP_LOGW(TAG, "Remote command: LoRa not implemented");
|
||||
#endif // HAS_LORA
|
||||
@@ -239,14 +276,10 @@ void get_config(uint8_t val[]) {
|
||||
|
||||
void get_status(uint8_t val[]) {
|
||||
ESP_LOGI(TAG, "Remote command: get device status");
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
uint16_t voltage = read_voltage();
|
||||
#else
|
||||
uint16_t voltage = 0;
|
||||
#endif
|
||||
payload.reset();
|
||||
payload.addStatus(voltage, uptime() / 1000, temperatureRead(), getFreeRAM(),
|
||||
rtc_get_reset_reason(0), rtc_get_reset_reason(1));
|
||||
payload.addStatus(read_voltage(), uptime() / 1000, temperatureRead(),
|
||||
getFreeRAM(), rtc_get_reset_reason(0),
|
||||
rtc_get_reset_reason(1));
|
||||
SendPayload(STATUSPORT, prio_high);
|
||||
};
|
||||
|
||||
@@ -274,6 +307,17 @@ void get_bme(uint8_t val[]) {
|
||||
#endif
|
||||
};
|
||||
|
||||
void get_batt(uint8_t val[]) {
|
||||
ESP_LOGI(TAG, "Remote command: get battery voltage");
|
||||
#if (defined BAT_MEASURE_ADC || defined HAS_PMU)
|
||||
payload.reset();
|
||||
payload.addVoltage(read_voltage());
|
||||
SendPayload(BATTPORT, prio_normal);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Battery voltage not supported");
|
||||
#endif
|
||||
};
|
||||
|
||||
void get_time(uint8_t val[]) {
|
||||
ESP_LOGI(TAG, "Remote command: get time");
|
||||
payload.reset();
|
||||
@@ -297,26 +341,28 @@ void set_flush(uint8_t val[]) {
|
||||
// format: opcode, function, #bytes params,
|
||||
// flag (true = do make settings persistent / false = don't)
|
||||
//
|
||||
cmd_t table[] = {
|
||||
static cmd_t table[] = {
|
||||
{0x01, set_rssi, 1, true}, {0x02, set_countmode, 1, true},
|
||||
{0x03, set_gps, 1, true}, {0x04, set_display, 1, true},
|
||||
{0x05, set_lorasf, 1, true}, {0x06, set_lorapower, 1, true},
|
||||
{0x05, set_loradr, 1, true}, {0x06, set_lorapower, 1, true},
|
||||
{0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 1, true},
|
||||
{0x09, set_reset, 1, true}, {0x0a, set_sendcycle, 1, true},
|
||||
{0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true},
|
||||
{0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true},
|
||||
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
|
||||
{0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false},
|
||||
{0x13, set_sensor, 2, true}, {0x80, get_config, 0, false},
|
||||
{0x81, get_status, 0, false}, {0x84, get_gps, 0, false},
|
||||
{0x13, set_sensor, 2, true}, {0x14, set_payloadmask, 1, true},
|
||||
{0x15, set_bme, 1, true}, {0x16, set_batt, 1, true},
|
||||
{0x80, get_config, 0, false}, {0x81, get_status, 0, false},
|
||||
{0x83, get_batt, 0, false}, {0x84, get_gps, 0, false},
|
||||
{0x85, get_bme, 0, false}, {0x86, get_time, 0, false},
|
||||
{0x87, set_time, 0, false}, {0x99, set_flush, 0, false}};
|
||||
|
||||
const uint8_t cmdtablesize =
|
||||
static const uint8_t cmdtablesize =
|
||||
sizeof(table) / sizeof(table[0]); // number of commands in command table
|
||||
|
||||
// check and execute remote command
|
||||
void rcommand(uint8_t cmd[], uint8_t cmdlength) {
|
||||
void rcommand(const uint8_t cmd[], const uint8_t cmdlength) {
|
||||
|
||||
if (cmdlength == 0)
|
||||
return;
|
||||
|
||||
+10
-7
@@ -10,9 +10,12 @@ void sendcycle() {
|
||||
// put data to send in RTos Queues used for transmit over channels Lora and SPI
|
||||
void SendPayload(uint8_t port, sendprio_t prio) {
|
||||
|
||||
MessageBuffer_t SendBuffer; // contains MessageSize, MessagePort, Message[]
|
||||
MessageBuffer_t
|
||||
SendBuffer; // contains MessageSize, MessagePort, MessagePrio, Message[]
|
||||
|
||||
SendBuffer.MessageSize = payload.getSize();
|
||||
SendBuffer.MessagePrio = prio;
|
||||
|
||||
switch (PAYLOAD_ENCODER) {
|
||||
case 1: // plain -> no mapping
|
||||
case 2: // packed -> no mapping
|
||||
@@ -38,20 +41,20 @@ void SendPayload(uint8_t port, sendprio_t prio) {
|
||||
default:
|
||||
SendBuffer.MessagePort = port;
|
||||
}
|
||||
memcpy(SendBuffer.Message, payload.getBuffer(), payload.getSize());
|
||||
memcpy(SendBuffer.Message, payload.getBuffer(), SendBuffer.MessageSize);
|
||||
|
||||
// enqueue message in device's send queues
|
||||
#if (HAS_LORA)
|
||||
lora_enqueuedata(&SendBuffer, prio);
|
||||
lora_enqueuedata(&SendBuffer);
|
||||
#endif
|
||||
#ifdef HAS_SPI
|
||||
spi_enqueuedata(&SendBuffer, prio);
|
||||
spi_enqueuedata(&SendBuffer);
|
||||
#endif
|
||||
|
||||
} // SendPayload
|
||||
|
||||
// interrupt triggered function to prepare payload to send
|
||||
void sendCounter() {
|
||||
void sendData() {
|
||||
|
||||
uint8_t bitmask = cfg.payloadmask;
|
||||
uint8_t mask = 1;
|
||||
@@ -115,7 +118,7 @@ void sendCounter() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef BAT_MEASURE_ADC
|
||||
#if (defined BAT_MEASURE_ADC || defined HAS_PMU)
|
||||
case BATT_DATA:
|
||||
payload.reset();
|
||||
payload.addVoltage(read_voltage());
|
||||
@@ -128,7 +131,7 @@ void sendCounter() {
|
||||
mask <<= 1;
|
||||
} // while (bitmask)
|
||||
|
||||
} // sendCounter()
|
||||
} // sendData()
|
||||
|
||||
void flushQueues() {
|
||||
#if (HAS_LORA)
|
||||
|
||||
+4
-2
@@ -56,7 +56,7 @@ void spi_slave_task(void *param) {
|
||||
memset(txbuf, 0, sizeof(txbuf));
|
||||
memset(rxbuf, 0, sizeof(rxbuf));
|
||||
|
||||
// wait until data to send arrivey
|
||||
// fetch next or wait for payload to send from queue
|
||||
if (xQueueReceive(SPISendQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||
continue;
|
||||
@@ -147,10 +147,12 @@ esp_err_t spi_init() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void spi_enqueuedata(MessageBuffer_t *message, sendprio_t prio) {
|
||||
void spi_enqueuedata(MessageBuffer_t *message) {
|
||||
// enqueue message in SPI send queue
|
||||
BaseType_t ret;
|
||||
MessageBuffer_t DummyBuffer;
|
||||
sendprio_t prio = message->MessagePrio;
|
||||
|
||||
switch (prio) {
|
||||
case prio_high:
|
||||
// clear space in queue if full, then fallthrough to normal
|
||||
|
||||
+53
-1
@@ -54,12 +54,64 @@ void calibrateTime(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
goto finish;
|
||||
|
||||
finish:
|
||||
|
||||
setMyTime(t, t_msec, timeSource); // set time
|
||||
setMyTime((uint32_t)t, t_msec, timeSource); // set time
|
||||
|
||||
} // calibrateTime()
|
||||
|
||||
// adjust system time, calibrate RTC and RTC_INT pps
|
||||
void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec,
|
||||
timesource_t mytimesource) {
|
||||
|
||||
// called with invalid timesource?
|
||||
if (mytimesource == _unsynced)
|
||||
return;
|
||||
|
||||
// increment t_sec only if t_msec > 1000
|
||||
time_t time_to_set = (time_t)(t_sec + t_msec / 1000);
|
||||
|
||||
// do we have a valid time?
|
||||
if (timeIsValid(time_to_set)) {
|
||||
|
||||
// if we have msec fraction, then wait until top of second with
|
||||
// millisecond precision
|
||||
if (t_msec % 1000) {
|
||||
time_to_set++;
|
||||
vTaskDelay(pdMS_TO_TICKS(1000 - t_msec % 1000));
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "[%0.3f] UTC epoch time: %d.%03d sec", millis() / 1000.0,
|
||||
time_to_set, t_msec % 1000);
|
||||
|
||||
// if we have got an external 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 (!defined GPS_INT && !defined RTC_INT)
|
||||
timerWrite(ppsIRQ, 0); // reset pps timer
|
||||
CLOCKIRQ(); // fire clock pps, this advances time 1 sec
|
||||
#endif
|
||||
|
||||
setTime(time_to_set); // set the time on top of second
|
||||
|
||||
timeSource = mytimesource; // set global variable
|
||||
timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync);
|
||||
ESP_LOGI(TAG, "[%0.3f] Timesync finished, time was set | source: %c",
|
||||
millis() / 1000.0, timeSetSymbols[timeSource]);
|
||||
} else {
|
||||
timesyncer.attach(TIME_SYNC_INTERVAL_RETRY * 60, timeSync);
|
||||
ESP_LOGI(TAG, "[%0.3f] Timesync failed, invalid time fetched | source: %c",
|
||||
millis() / 1000.0, timeSetSymbols[timeSource]);
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to setup a pulse per second for time synchronisation
|
||||
uint8_t timepulse_init() {
|
||||
|
||||
|
||||
+2
-88
@@ -108,7 +108,7 @@ void process_timesync_req(void *taskparameter) {
|
||||
payload.addByte(0x99);
|
||||
SendPayload(RCMDPORT, prio_high);
|
||||
// ...send a alive open a receive window for last time_sync_answer
|
||||
// LMIC_sendAlive();
|
||||
LMIC_sendAlive();
|
||||
}
|
||||
} // end of for loop to collect timestamp samples
|
||||
|
||||
@@ -181,7 +181,7 @@ int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) {
|
||||
// the 5th byte contains the fractional seconds in 2^-8 second steps
|
||||
// (= 1/250th sec), we convert this to ms
|
||||
uint16_t timestamp_msec = 4 * buf[4];
|
||||
// pointers to 4 bytes 4 bytes containing UTC seconds since unix epoch, msb
|
||||
// pointers to 4 bytes containing UTC seconds since unix epoch, msb
|
||||
uint32_t timestamp_sec, *timestamp_ptr;
|
||||
|
||||
// convert buffer to uint32_t, octet order is big endian
|
||||
@@ -210,92 +210,6 @@ int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) {
|
||||
}
|
||||
}
|
||||
|
||||
// adjust system time, calibrate RTC and RTC_INT pps
|
||||
void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec,
|
||||
timesource_t mytimesource) {
|
||||
|
||||
t_sec ++;
|
||||
time_t time_to_set = (time_t)(t_sec);
|
||||
|
||||
// increment t_sec only if t_msec > 1000
|
||||
time_to_set = (time_t)(t_sec + t_msec / 1000);
|
||||
|
||||
// do we have a valid time?
|
||||
if (timeIsValid(time_to_set)) {
|
||||
|
||||
// if we have msec fraction, then wait until top of second with
|
||||
// millisecond precision
|
||||
if (t_msec % 1000) {
|
||||
time_to_set++;
|
||||
vTaskDelay(pdMS_TO_TICKS(1000 - t_msec % 1000));
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "[%0.3f] UTC epoch time: %d.%03d sec", millis() / 1000.0,
|
||||
time_to_set, t_msec % 1000);
|
||||
|
||||
// if we have got an external 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 (!defined GPS_INT && !defined RTC_INT)
|
||||
timerWrite(ppsIRQ, 0); // reset pps timer
|
||||
CLOCKIRQ(); // fire clock pps, this advances time 1 sec
|
||||
#endif
|
||||
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
if(gettimeofday(&tv, &tz) != 0) {
|
||||
ESP_LOGE(TAG, "ERROR gettimeofday");
|
||||
}
|
||||
struct timeval beforeTime = tv;
|
||||
|
||||
struct timeval nowTime;
|
||||
nowTime.tv_sec = t_sec;
|
||||
nowTime.tv_usec = t_msec;
|
||||
if(settimeofday(&nowTime, &tz) != 0) {
|
||||
ESP_LOGE(TAG, "ERROR settimeofday");
|
||||
}
|
||||
|
||||
struct timeval diff;
|
||||
diff.tv_sec = nowTime.tv_sec-beforeTime.tv_sec;
|
||||
diff.tv_usec = nowTime.tv_usec-beforeTime.tv_usec;
|
||||
|
||||
// sum up diff_s and diff_ms to one ms value
|
||||
int32_t diff_s = diff.tv_sec;
|
||||
int32_t diff_ms = diff.tv_usec/1000;
|
||||
int32_t diff_ms_remain = diff_ms / 1000;
|
||||
diff_s += diff_ms_remain;
|
||||
diff_ms += -1000*diff_ms_remain;
|
||||
if(diff_ms < 0) {
|
||||
diff_s --;
|
||||
diff_ms += 1000;
|
||||
}
|
||||
// cap diff at 24h (= 86,400s)
|
||||
diff_s = diff_s % 86400;
|
||||
int32_t timediff_ms = diff_s * 1000 + diff_ms;
|
||||
|
||||
// send diffTime
|
||||
payload.reset();
|
||||
payload.addTimeDiff(timediff_ms);
|
||||
SendPayload(TIMEDIFFPORT, prio_high);
|
||||
ESP_LOGI(TAG, "timediff_ms: %d", timediff_ms);
|
||||
|
||||
timeSource = mytimesource; // set global variable
|
||||
timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync);
|
||||
time_uart_send_start();
|
||||
ESP_LOGI(TAG, "[%0.3f] Timesync finished, time was set | source: %c",
|
||||
millis() / 1000.0, timeSetSymbols[timeSource]);
|
||||
} else {
|
||||
timesyncer.attach(TIME_SYNC_INTERVAL_RETRY * 60, timeSync);
|
||||
ESP_LOGI(TAG, "[%0.3f] Timesync failed, invalid time fetched | source: %c",
|
||||
millis() / 1000.0, timeSetSymbols[timeSource]);
|
||||
}
|
||||
}
|
||||
|
||||
// create task for timeserver handshake processing, called from main.cpp
|
||||
void timesync_init() {
|
||||
xTaskCreatePinnedToCore(process_timesync_req, // task function
|
||||
|
||||
+4
-4
@@ -57,7 +57,7 @@ void wifi_sniffer_init(void) {
|
||||
wificfg.nvs_enable = 0; // we don't need any wifi settings from NVRAM
|
||||
wificfg.wifi_task_core_id = 0; // we want wifi task running on core 0
|
||||
|
||||
//wifi_promiscuous_filter_t filter = {
|
||||
// wifi_promiscuous_filter_t filter = {
|
||||
// .filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // only MGMT frames
|
||||
// .filter_mask = WIFI_PROMIS_FILTER_MASK_ALL}; // we use all frames
|
||||
|
||||
@@ -71,9 +71,9 @@ void wifi_sniffer_init(void) {
|
||||
ESP_ERROR_CHECK(
|
||||
esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
|
||||
ESP_ERROR_CHECK(esp_wifi_stop());
|
||||
ESP_ERROR_CHECK(
|
||||
esp_wifi_set_promiscuous_filter(&filter)); // set frame filter
|
||||
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); // no modem power saving
|
||||
ESP_ERROR_CHECK(esp_wifi_start()); // must be started to be able to switch ch
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filter)); // set frame filter
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); // now switch on monitor mode
|
||||
|
||||
|
||||
Reference in new issue
Block a user