merged v2.0.17
This commit is contained in:
commit
21d94247bd
10
README.md
10
README.md
@ -83,12 +83,16 @@ By default bluetooth sniffing not installed (#define *BLECOUNTER* 0 in paxcounte
|
||||
|
||||
# Preparing
|
||||
|
||||
## Install Platformio
|
||||
|
||||
Install <A HREF="https://platformio.org/">PlatformIO IDE for embedded development</A> to make this project. Platformio integrates with your favorite IDE, choose eg. Visual Studio, Atom, Eclipse etc.
|
||||
|
||||
Compile time configuration is spread across several files. Before compiling the code, edit or create the following files:
|
||||
|
||||
## platformio_orig.ini
|
||||
Edit `platformio_orig.ini` and select desired hardware target in section boards. To add a new board, create an appropriate hardware abstraction layer file in hal subdirectory, and add a pointer to this file in sections board. Copy or rename to `platformio.ini`.
|
||||
## platformio.ini
|
||||
Edit `platformio_orig.ini` and select desired hardware target in section boards. To add a new board, create an appropriate hardware abstraction layer file in hal subdirectory, and add a pointer to this file in sections board. Copy or rename to `platformio.ini` in the root directory of the project. Now start Platformio. Note: Platformio is looking for `platformio.ini` in the root directory and won't start if it does not find this file.
|
||||
|
||||
## src/paxcounter_orig.conf
|
||||
## src/paxcounter.conf
|
||||
Edit `src/paxcounter_orig.conf` and tailor settings in this file according to your needs and use case. Please take care of the duty cycle regulations of the LoRaWAN network you're going to use. Copy or rename to `src/paxcounter.conf`.
|
||||
|
||||
If your device has a **real time clock** it can be updated bei either LoRaWAN network or GPS time, according to settings *TIME_SYNC_INTERVAL* and *TIME_SYNC_LORAWAN* in `paxcounter.conf`.
|
||||
|
@ -1,11 +1,12 @@
|
||||
#ifndef _CONFIGMANAGER_H
|
||||
#define _CONFIGMANAGER_H
|
||||
|
||||
#include <Preferences.h>
|
||||
#include "globals.h"
|
||||
#include <Preferences.h>
|
||||
|
||||
void saveConfig(bool erase = false);
|
||||
bool loadConfig(void);
|
||||
void eraseConfig(void);
|
||||
int version_compare(const String v1, const String v2);
|
||||
|
||||
#endif
|
@ -60,8 +60,10 @@ enum runmode_t {
|
||||
};
|
||||
|
||||
// Struct holding devices's runtime configuration
|
||||
// using packed to avoid compiler padding, because struct will be memcpy'd to byte array
|
||||
// using packed to avoid compiler padding, because struct will be memcpy'd to
|
||||
// byte array
|
||||
typedef struct __attribute__((packed)) {
|
||||
char version[10]; // Firmware version
|
||||
uint8_t loradr; // 0-15, lora datarate
|
||||
uint8_t txpower; // 2-15, lora tx power
|
||||
uint8_t adrmode; // 0=disabled, 1=enabled
|
||||
@ -80,11 +82,12 @@ typedef struct __attribute__((packed)) {
|
||||
uint8_t monitormode; // 0=disabled, 1=enabled
|
||||
uint8_t runmode; // 0=normal, 1=update
|
||||
uint8_t payloadmask; // bitswitches for payload data
|
||||
|
||||
uint8_t enscount; // 0=disabled 1= enabled
|
||||
char version[10]; // Firmware version
|
||||
|
||||
#ifdef HAS_BME680
|
||||
uint8_t
|
||||
bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1]; // BSEC state for BME680 sensor
|
||||
uint8_t bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1]; // BSEC state for BME680 sensor
|
||||
#endif
|
||||
} configData_t;
|
||||
|
||||
|
@ -6,17 +6,15 @@
|
||||
#include "globals.h"
|
||||
#include "led.h"
|
||||
#include "display.h"
|
||||
#include "configmanager.h"
|
||||
|
||||
#include <Update.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <BintrayClient.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
int do_ota_update();
|
||||
void start_ota_update();
|
||||
int version_compare(const String v1, const String v2);
|
||||
void ota_display(const uint8_t row, const std::string status,
|
||||
const std::string msg);
|
||||
void show_progress(unsigned long current, unsigned long size);
|
||||
|
@ -46,7 +46,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I
|
||||
|
||||
[common]
|
||||
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
||||
release_version = 2.0.16
|
||||
release_version = 2.0.17
|
||||
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
||||
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||
debug_level = 3
|
||||
|
@ -16,16 +16,22 @@ static const char TAG[] = __FILE__;
|
||||
|
||||
Preferences nvram;
|
||||
|
||||
static const char cfgMagicBytes[] = {0x21, 0x76, 0x87, 0x32, 0xf3};
|
||||
static const uint8_t cfgMagicBytes[] = {0x21, 0x76, 0x87, 0x32, 0xf4};
|
||||
static const size_t cfgLen = sizeof(cfg), cfgLen2 = sizeof(cfgMagicBytes);
|
||||
static char buffer[cfgLen + cfgLen2];
|
||||
static uint8_t buffer[cfgLen + cfgLen2];
|
||||
|
||||
// populate runtime config with device factory settings
|
||||
//
|
||||
// configuration frame structure in NVRAM;
|
||||
// 1. version header [10 bytes, containing version string]
|
||||
// 2. user settings [cfgLen bytes, containing default runtime settings
|
||||
// (configData_t cfg)]
|
||||
// 3. magicByte [cfgLen2 bytes, containing a fixed identifier]
|
||||
|
||||
// populate runtime config with factory settings
|
||||
static void defaultConfig(configData_t *myconfig) {
|
||||
char version[10];
|
||||
snprintf(version, 10, "%-10s", PROGVERSION);
|
||||
memcpy(myconfig->version, &PROGVERSION, 10); // Firmware version
|
||||
|
||||
// factory settings
|
||||
// device factory settings
|
||||
myconfig->loradr = LORADRDEFAULT; // 0-15, lora datarate, see paxcounter.conf
|
||||
myconfig->txpower = LORATXPOWDEFAULT; // 0-15, lora tx power
|
||||
myconfig->adrmode = 1; // 0=disabled, 1=enabled
|
||||
@ -56,6 +62,11 @@ static void defaultConfig(configData_t *myconfig) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// migrate runtime configuration from earlier to current version
|
||||
static void migrateConfig(void) {
|
||||
// currently no configuration migration rules are implemented
|
||||
}
|
||||
|
||||
// save current configuration from RAM to NVRAM
|
||||
void saveConfig(bool erase) {
|
||||
ESP_LOGI(TAG, "Storing settings to NVRAM...");
|
||||
@ -84,36 +95,65 @@ void saveConfig(bool erase) {
|
||||
// load configuration from NVRAM into RAM and make it current
|
||||
bool loadConfig() {
|
||||
|
||||
ESP_LOGI(TAG, "Loading device runtime configuration from NVRAM...");
|
||||
ESP_LOGI(TAG, "Loading device configuration from NVRAM...");
|
||||
|
||||
if (!nvram.begin(DEVCONFIG, true)) {
|
||||
ESP_LOGW(TAG, "NVRAM initialized, device starts with factory settings");
|
||||
ESP_LOGI(TAG, "NVRAM initialized, device starts with factory settings");
|
||||
eraseConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// simple check that runtime config data matches
|
||||
if (nvram.getBytesLength(DEVCONFIG) != (cfgLen + cfgLen2)) {
|
||||
ESP_LOGE(TAG, "configuration invalid");
|
||||
return false;
|
||||
// simple check that runtime config data matches
|
||||
if (nvram.getBytesLength(DEVCONFIG) != (cfgLen + cfgLen2)) {
|
||||
ESP_LOGE(TAG, "Configuration invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// load device runtime config from nvram and copy it to byte array
|
||||
nvram.getBytes(DEVCONFIG, buffer, cfgLen + cfgLen2);
|
||||
nvram.end();
|
||||
// validate configuration by checking magic bytes at end of array
|
||||
if (memcmp(buffer + cfgLen, &cfgMagicBytes, cfgLen2) != 0) {
|
||||
ESP_LOGW(TAG, "No configuration found");
|
||||
return false;
|
||||
// load device runtime config from nvram and copy it to byte array
|
||||
nvram.getBytes(DEVCONFIG, buffer, cfgLen + cfgLen2);
|
||||
nvram.end();
|
||||
|
||||
} else {
|
||||
// copy byte array into runtime cfg struct
|
||||
memcpy(&cfg, buffer, cfgLen);
|
||||
ESP_LOGI(TAG, "Runtime configuration loaded");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// validate loaded configuration by checking magic bytes at end of array
|
||||
if (memcmp(buffer + cfgLen, &cfgMagicBytes, cfgLen2) != 0) {
|
||||
ESP_LOGW(TAG, "No configuration found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy loaded configuration into runtime cfg struct
|
||||
memcpy(&cfg, buffer, cfgLen);
|
||||
ESP_LOGI(TAG, "Runtime configuration v%s loaded", cfg.version);
|
||||
|
||||
// check if config version matches current firmware version
|
||||
switch (version_compare(PROGVERSION, cfg.version)) {
|
||||
case -1: // device configuration belongs to newer than current firmware
|
||||
ESP_LOGE(TAG, "Incompatible device configuration");
|
||||
return false;
|
||||
case 1: // device configuration belongs to older than current firmware
|
||||
ESP_LOGW(TAG, "Device was updated, attempt to migrate configuration");
|
||||
migrateConfig();
|
||||
return true;
|
||||
default: // device configuration version matches current firmware version
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void eraseConfig(void) { saveConfig(true); }
|
||||
// helper function to convert strings into lower case
|
||||
bool comp(char s1, char s2) { return (tolower(s1) < tolower(s2)); }
|
||||
|
||||
// helper function to lexicographically compare two versions. Returns 1 if v2
|
||||
// is smaller, -1 if v1 is smaller, 0 if equal
|
||||
int version_compare(const String v1, const String v2) {
|
||||
|
||||
if (v1 == v2)
|
||||
return 0;
|
||||
|
||||
const char *a1 = v1.c_str(), *a2 = v2.c_str();
|
||||
|
||||
if (std::lexicographical_compare(a1, a1 + strlen(a1), a2, a2 + strlen(a2),
|
||||
comp))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void eraseConfig(void) { saveConfig(true); }
|
@ -12,7 +12,10 @@ static const char TAG[] = __FILE__;
|
||||
// thus precision is only +/- 1 second
|
||||
|
||||
TinyGPSPlus gps;
|
||||
TinyGPSCustom gpstime(gps, "GPZDA", 1); // field 1 = UTC time
|
||||
TinyGPSCustom gpstime(gps, "GPZDA", 1); // field 1 = UTC time (hhmmss.ss)
|
||||
TinyGPSCustom gpsday(gps, "GPZDA", 2); // field 2 = day (01..31)
|
||||
TinyGPSCustom gpsmonth(gps, "GPZDA", 3); // field 3 = month (01..12)
|
||||
TinyGPSCustom gpsyear(gps, "GPZDA", 4); // field 4 = year (4-digit)
|
||||
static const String ZDA_Request = "$EIGPQ,ZDA*39\r\n";
|
||||
TaskHandle_t GpsTask;
|
||||
|
||||
@ -93,7 +96,7 @@ bool gps_hasfix() {
|
||||
gps.altitude.age() < 4000);
|
||||
}
|
||||
|
||||
// function to fetch current time from struct; note: this is costly
|
||||
// function to poll current time from GPS data; note: this is costly
|
||||
time_t get_gpstime(uint16_t *msec) {
|
||||
|
||||
time_t time_sec = 0;
|
||||
@ -102,34 +105,30 @@ time_t get_gpstime(uint16_t *msec) {
|
||||
#ifdef GPS_SERIAL
|
||||
GPS_Serial.print(ZDA_Request);
|
||||
// wait for gps NMEA answer
|
||||
vTaskDelay(tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL));
|
||||
// vTaskDelay(tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL));
|
||||
#elif defined GPS_I2C
|
||||
Wire.print(ZDA_Request);
|
||||
#endif
|
||||
|
||||
// did we get a current time?
|
||||
if (gpstime.isUpdated() && gpstime.isValid()) {
|
||||
// did we get a current date & time?
|
||||
if (gpstime.isUpdated() && gpstime.isValid() && gpsday.isValid()) {
|
||||
|
||||
tmElements_t tm;
|
||||
|
||||
String rawtime = gpstime.value();
|
||||
uint32_t time_bcd = rawtime.toFloat() * 100;
|
||||
uint32_t time_bcd = atof(gpstime.value()) * 100;
|
||||
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
|
||||
|
||||
ESP_LOGD(TAG, "time [bcd]: %u", time_bcd);
|
||||
|
||||
tm.Second = (time_bcd / 100) % 100; // second
|
||||
tm.Minute = (time_bcd / 10000) % 100; // minute
|
||||
tm.Hour = time_bcd / 1000000; // hour
|
||||
tm.Day = gps.date.day(); // day
|
||||
tm.Month = gps.date.month(); // month
|
||||
tm.Year = year; // year
|
||||
tm.Day = atoi(gpsday.value()); // day
|
||||
tm.Month = atoi(gpsmonth.value()); // month
|
||||
tm.Year = CalendarYrToTm(
|
||||
atoi(gpsyear.value())); // year offset from 1970 in microTime.h
|
||||
|
||||
// add protocol delay to time with millisecond precision
|
||||
time_sec = makeTime(tm) + delay_ms / 1000;
|
||||
time_sec = makeTime(tm) + delay_ms / 1000 - 1;
|
||||
*msec = (delay_ms % 1000) ? delay_ms % 1000 : 0;
|
||||
}
|
||||
|
||||
@ -163,15 +162,15 @@ void gps_loop(void *pvParameters) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// if time hasn't been synchronised yet, and we have a valid GPS time,
|
||||
// update time from GPS.
|
||||
if (timeSource == _unsynced && gpstime.isUpdated() && gpstime.isValid()) {
|
||||
// (only) while device time is not set or unsynched, and we have a valid GPS
|
||||
// time, we trigger a device time update to poll time from GPS
|
||||
if (timeSource == _unsynced && gpstime.isUpdated() && gpstime.isValid() &&
|
||||
gpsday.isValid())
|
||||
calibrateTime();
|
||||
}
|
||||
|
||||
} // if
|
||||
|
||||
// show NMEA data in verbose mode, useful for debugging GPS, bu tvery noisy
|
||||
// show NMEA data in verbose mode, useful only for debugging GPS, very noisy
|
||||
// ESP_LOGV(TAG, "GPS NMEA data: passed %u / failed: %u / with fix: %u",
|
||||
// gps.passedChecksum(), gps.failedChecksum(),
|
||||
// gps.sentencesWithFix());
|
||||
|
18
src/ota.cpp
18
src/ota.cpp
@ -328,22 +328,4 @@ void show_progress(unsigned long current, unsigned long size) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// helper function to convert strings into lower case
|
||||
bool comp(char s1, char s2) { return tolower(s1) < tolower(s2); }
|
||||
|
||||
// helper function to lexicographically compare two versions. Returns 1 if v2 is
|
||||
// smaller, -1 if v1 is smaller, 0 if equal
|
||||
int version_compare(const String v1, const String v2) {
|
||||
|
||||
if (v1 == v2)
|
||||
return 0;
|
||||
|
||||
const char *a1 = v1.c_str(), *a2 = v2.c_str();
|
||||
|
||||
if (lexicographical_compare(a1, a1 + strlen(a1), a2, a2 + strlen(a2), comp))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // USE_OTA
|
135
src/platformio_orig.ini
Normal file
135
src/platformio_orig.ini
Normal file
@ -0,0 +1,135 @@
|
||||
; PlatformIO Project Configuration File
|
||||
; NOTE: PlatformIO v4 is needed!
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; http://docs.platformio.org/page/projectconf.html
|
||||
|
||||
|
||||
; ---> SELECT THE TARGET PLATFORM HERE! <---
|
||||
[board]
|
||||
halfile = generic.h
|
||||
;halfile = ebox.h
|
||||
;halfile = eboxtube.h
|
||||
;halfile = ecopower.h
|
||||
;halfile = heltec.h
|
||||
;halfile = heltecv2.h
|
||||
;halfile = ttgov1.h
|
||||
;halfile = ttgov2.h
|
||||
;halfile = ttgov21old.h
|
||||
;halfile = ttgov21new.h
|
||||
;halfile = ttgofox.h
|
||||
;halfile = ttgobeam.h
|
||||
;halfile = ttgobeam10.h
|
||||
;halfile = fipy.h
|
||||
;halfile = lopy.h
|
||||
;halfile = lopy4.h
|
||||
;halfile = lolin32litelora.h
|
||||
;halfile = lolin32lora.h
|
||||
;halfile = lolin32lite.h
|
||||
;halfile = wemos32oled.h
|
||||
;halfile = wemos32matrix.h
|
||||
;halfile = octopus32.h
|
||||
;halfile = tinypico.h
|
||||
;halfile = tinypicomatrix.h
|
||||
;halfile = m5core.h
|
||||
;halfile = m5fire.h
|
||||
;halfile = olimexpoeiso.h
|
||||
|
||||
[platformio]
|
||||
; upload firmware to board with usb cable
|
||||
default_envs = usb
|
||||
; upload firmware to a jfrog bintray repository
|
||||
;default_envs = ota
|
||||
; use latest versions of libraries
|
||||
;default_envs = dev
|
||||
description = Paxcounter is a device for metering passenger flows in realtime. It counts how many mobile devices are around.
|
||||
|
||||
[common]
|
||||
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
||||
release_version = 2.0.16
|
||||
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
||||
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||
debug_level = 3
|
||||
extra_scripts = pre:build.py
|
||||
otakeyfile = ota.conf
|
||||
lorakeyfile = loraconf.h
|
||||
lmicconfigfile = lmic_config.h
|
||||
platform_espressif32 = espressif32@2.0.0
|
||||
monitor_speed = 115200
|
||||
upload_speed = 115200 ; set by build.py and taken from hal file
|
||||
display_library = ; set by build.py and taken from hal file
|
||||
lib_deps_lora =
|
||||
mcci-catena/MCCI LoRaWAN LMIC library @ ^3.2.0
|
||||
lib_deps_display =
|
||||
bitbank2/OneBitDisplay @ 1.7.2
|
||||
ricmoo/QRCode @ ^0.0.1
|
||||
bodmer/TFT_eSPI @ ^2.2.20
|
||||
lib_deps_ledmatrix =
|
||||
seeed-studio/Ultrathin_LED_Matrix @ ^1.0.0
|
||||
lib_deps_rgbled =
|
||||
roboticsbrno/SmartLeds @ ^1.2.1
|
||||
lib_deps_gps =
|
||||
mikalhart/TinyGPSPlus @ ^1.0.2
|
||||
lib_deps_sensors =
|
||||
adafruit/Adafruit Unified Sensor @ ^1.1.4
|
||||
adafruit/Adafruit BME280 Library @ ^2.1.1
|
||||
adafruit/Adafruit BMP085 Library @ ^1.1.0
|
||||
boschsensortec/BSEC Software Library @ 1.5.1474
|
||||
https://github.com/ricki-z/SDS011.git
|
||||
lib_deps_basic =
|
||||
bblanchon/ArduinoJson @ <6
|
||||
jchristensen/Timezone @ ^1.2.4
|
||||
makuna/RTC @ ^2.3.5
|
||||
spacehuhn/SimpleButton
|
||||
lewisxhe/AXP202X_Library @ ^1.1.2
|
||||
geeksville/esp32-micro-sdcard @ ^0.1.1
|
||||
256dpi/MQTT @ ^2.4.7
|
||||
lib_deps_all =
|
||||
${common.lib_deps_basic}
|
||||
${common.lib_deps_lora}
|
||||
${common.lib_deps_display}
|
||||
${common.lib_deps_rgbled}
|
||||
${common.lib_deps_gps}
|
||||
${common.lib_deps_sensors}
|
||||
${common.lib_deps_ledmatrix}
|
||||
build_flags_basic =
|
||||
-include "src/hal/${board.halfile}"
|
||||
-include "src/paxcounter.conf"
|
||||
-w
|
||||
'-DCORE_DEBUG_LEVEL=${common.debug_level}'
|
||||
'-DLOG_LOCAL_LEVEL=${common.debug_level}'
|
||||
'-DPROGVERSION="${common.release_version}"'
|
||||
build_flags_sensors =
|
||||
-Llib/Bosch-BSEC/src/esp32/
|
||||
-lalgobsec
|
||||
build_flags_all =
|
||||
${common.build_flags_basic}
|
||||
${common.build_flags_sensors}
|
||||
-mfix-esp32-psram-cache-issue
|
||||
|
||||
[env]
|
||||
lib_ldf_mode = deep ; #632 Fixes compiler error with OneBitDisplay library
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = min_spiffs.csv
|
||||
upload_speed = ${common.upload_speed}
|
||||
;upload_port = COM8
|
||||
platform = ${common.platform_espressif32}
|
||||
lib_deps = ${common.lib_deps_all}
|
||||
build_flags = ${common.build_flags_all}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
monitor_filters = time, esp32_exception_decoder, default
|
||||
|
||||
[env:ota]
|
||||
upload_protocol = custom
|
||||
|
||||
[env:usb]
|
||||
upload_protocol = esptool
|
||||
|
||||
[env:dev]
|
||||
upload_protocol = esptool
|
||||
build_type = debug
|
||||
platform = https://github.com/platformio/platform-espressif32.git#develop
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git
|
Loading…
Reference in New Issue
Block a user