This commit is contained in:
cyberman54 committed 2021-02-02 23:23:25 +01:00
commit b2931c148d
40 files changed
+936 -427

No files matched your search

+467
View File
@@ -0,0 +1,467 @@
[
{
"id": "7bc3eb4f.fe4b64",
"type": "mqtt in",
"z": "c26229c6.2d1ae8",
"name": "Olimex",
"topic": "paxout/#",
"qos": "2",
"datatype": "utf8",
"broker": "bd56b04d.db0ff",
"x": 190,
"y": 160,
"wires": [
[
"d0276db6.83c46"
]
]
},
{
"id": "4f59740b.296b7c",
"type": "debug",
"z": "c26229c6.2d1ae8",
"name": "data",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 1050,
"y": 280,
"wires": []
},
{
"id": "f10f8199.25183",
"type": "binary",
"z": "c26229c6.2d1ae8",
"name": "wifi",
"property": "payload",
"pattern": "l16, x16",
"x": 630,
"y": 100,
"wires": [
[
"800f5faa.15155"
]
]
},
{
"id": "df4bdce5.dc219",
"type": "switch",
"z": "c26229c6.2d1ae8",
"name": "Ports",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "paxout/1",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/2",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/3",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/4",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/5",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/6",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/7",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/8",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/9",
"vt": "str"
},
{
"t": "eq",
"v": "paxout/10",
"vt": "str"
},
{
"t": "eq",
"v": "status",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 11,
"x": 370,
"y": 260,
"wires": [
[
"f10f8199.25183"
],
[
"e2974f79.55d5b"
],
[
"5f6987dd.b89378"
],
[],
[
"eaca83c4.5fcaf"
],
[],
[],
[
"7b6cbc9d.18fe44"
],
[
"d269537.4738fb"
],
[
"409e4762.71ff68"
],
[
"13fbfc5d.40dcc4"
]
]
},
{
"id": "eaca83c4.5fcaf",
"type": "binary",
"z": "c26229c6.2d1ae8",
"name": "button",
"property": "payload",
"pattern": "b8 => button",
"x": 630,
"y": 280,
"wires": [
[
"a6037445.eb8ac8"
]
]
},
{
"id": "409e4762.71ff68",
"type": "binary",
"z": "c26229c6.2d1ae8",
"name": "cwa",
"property": "payload",
"pattern": "l16 => cwa",
"x": 630,
"y": 140,
"wires": [
[
"2966fd1c.0b33d2"
]
]
},
{
"id": "d0276db6.83c46",
"type": "base64",
"z": "c26229c6.2d1ae8",
"name": "Decode",
"action": "",
"property": "payload",
"x": 200,
"y": 260,
"wires": [
[
"df4bdce5.dc219"
]
]
},
{
"id": "13fbfc5d.40dcc4",
"type": "binary",
"z": "c26229c6.2d1ae8",
"name": "Connection",
"property": "payload",
"pattern": "b8[19]|str(\"ascii\")",
"x": 650,
"y": 440,
"wires": [
[
"4f59740b.296b7c"
]
]
},
{
"id": "800f5faa.15155",
"type": "ui_chart",
"z": "c26229c6.2d1ae8",
"name": "pax",
"group": "6838565d.06bf08",
"order": 1,
"width": 0,
"height": 0,
"label": "Pax [Wifi]",
"chartType": "line",
"legend": "false",
"xformat": "dd HH:mm",
"interpolate": "linear",
"nodata": "Noch keine Daten",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": 1,
"removeOlderPoints": "",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"outputs": 1,
"x": 810,
"y": 100,
"wires": [
[]
]
},
{
"id": "2966fd1c.0b33d2",
"type": "ui_chart",
"z": "c26229c6.2d1ae8",
"name": "cwa",
"group": "6838565d.06bf08",
"order": 1,
"width": 0,
"height": 0,
"label": "CWA",
"chartType": "line",
"legend": "false",
"xformat": "dd HH:mm",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": 1,
"removeOlderPoints": "",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"outputs": 1,
"x": 810,
"y": 140,
"wires": [
[]
]
},
{
"id": "a6037445.eb8ac8",
"type": "ui_toast",
"z": "c26229c6.2d1ae8",
"position": "top right",
"displayTime": "3",
"highlight": "",
"sendall": true,
"outputs": 0,
"ok": "OK",
"cancel": "",
"raw": false,
"topic": "Button",
"name": "Popup",
"x": 810,
"y": 280,
"wires": []
},
{
"id": "b4478f8.f8b747",
"type": "mqtt out",
"z": "c26229c6.2d1ae8",
"name": "Olimex",
"topic": "paxin",
"qos": "",
"retain": "",
"broker": "bd56b04d.db0ff",
"x": 190,
"y": 480,
"wires": []
},
{
"id": "e2974f79.55d5b",
"type": "binary",
"z": "c26229c6.2d1ae8",
"name": "device status",
"property": "payload",
"pattern": "l16 => voltage,\nl64 => uptime,\nb8 => temperature,\nl32 => ram,\nb8 => reset0,\nb8 => reset1",
"x": 650,
"y": 200,
"wires": [
[
"4f59740b.296b7c"
]
]
},
{
"id": "5f6987dd.b89378",
"type": "binary",
"z": "c26229c6.2d1ae8",
"name": "device config",
"property": "payload",
"pattern": "b8 => loradr,\nb8 => txPower,\nl16 => rssilimit,\nb8 => sendcycle,\nb8 => wifichancycle,\nb8 => blescantime,\nb8 => rgblum,\nb8 => configmask,\nb8 => payloadmask,\nb8z|str(\"ascii\") => version",
"x": 650,
"y": 240,
"wires": [
[
"4f59740b.296b7c"
]
]
},
{
"id": "7b6cbc9d.18fe44",
"type": "binary",
"z": "c26229c6.2d1ae8",
"name": "battery",
"property": "payload",
"pattern": "l16 => voltage",
"x": 630,
"y": 360,
"wires": [
[
"4f59740b.296b7c"
]
]
},
{
"id": "d269537.4738fb",
"type": "binary",
"z": "c26229c6.2d1ae8",
"name": "time",
"property": "payload",
"pattern": "l32 => unixtime",
"x": 630,
"y": 400,
"wires": [
[
"4f59740b.296b7c"
]
]
},
{
"id": "ce0cb32b.b7b96",
"type": "base64",
"z": "c26229c6.2d1ae8",
"name": "Encode",
"action": "",
"property": "payload",
"x": 200,
"y": 420,
"wires": [
[
"b4478f8.f8b747"
]
]
},
{
"id": "c246a129.eeb5e",
"type": "inject",
"z": "c26229c6.2d1ae8",
"name": "rcmd",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "paxin",
"payload": "[128, 129]",
"payloadType": "bin",
"x": 190,
"y": 360,
"wires": [
[
"ce0cb32b.b7b96"
]
]
},
{
"id": "bd56b04d.db0ff",
"type": "mqtt-broker",
"name": "Shiftr.io",
"broker": "public.cloud.shiftr.io",
"port": "1883",
"clientid": "",
"usetls": false,
"compatmode": false,
"keepalive": "60",
"cleansession": true,
"birthTopic": "paxout/status",
"birthQos": "0",
"birthPayload": "on",
"closeTopic": "paxout/status",
"closeQos": "0",
"closePayload": "off",
"willTopic": "paxout/status",
"willQos": "0",
"willPayload": "unknown"
},
{
"id": "6838565d.06bf08",
"type": "ui_group",
"name": "MQTT",
"tab": "ad5894fa.466c58",
"order": 1,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "ad5894fa.466c58",
"type": "ui_tab",
"name": "Paxcounter",
"icon": "people",
"order": 4
}
]
File renamed without changes.
File renamed without changes.
+1 -1
View File
@@ -262,7 +262,7 @@ var bitmap2 = function (byte) {
}
var i = bytesToInt(byte);
var bm = ('00000000' + Number(i).toString(2)).substr(-8).split('').map(Number).map(Boolean);
return ['battery', 'sensor3', 'sensor2', 'sensor1', 'counter', 'bme', 'alarm', 'gps']
return ['battery', 'sensor3', 'sensor2', 'sensor1', 'gps', 'bme', 'alarm', 'counter']
.reduce(function (obj, pos, index) {
obj[pos] = +bm[index];
return obj;
+1 -2
View File
@@ -277,12 +277,11 @@ void start_BLEscan(void) {
// Register callback function for capturing bluetooth packets
register_ble_callback(false);
ESP_LOGI(TAG, "Bluetooth scanner started");
#endif // BLECOUNTER
} else {
ESP_LOGE(TAG, "Bluetooth controller start failed. Resetting device");
do_reset(true);
}
#endif // BLECOUNTER
} // start_BLEscan
void stop_BLEscan(void) {
+11 -54
View File
@@ -46,10 +46,10 @@ Adafruit_BMP085 bmp; // I2C
void setBMEIRQ() { xTaskNotify(irqHandlerTask, BME_IRQ, eSetBits); }
// initialize MEMS sensor
// return = 0 -> error / return = 1 -> success
int bme_init(void) {
// return = 0 -> error / return = 1 -> success
int rc = 1;
int rc = 0;
#ifdef HAS_BME680
// block i2c bus access
@@ -63,76 +63,33 @@ int bme_init(void) {
iaqSensor.version.minor_bugfix);
iaqSensor.setConfig(bsec_config_iaq);
if (checkIaqSensorStatus())
ESP_LOGI(TAG, "BME680 sensor found and initialized");
else {
ESP_LOGE(TAG, "BME680 sensor not found");
rc = 0;
goto finish;
}
loadState();
iaqSensor.setTemperatureOffset((float)BME_TEMP_OFFSET);
iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
if (checkIaqSensorStatus())
ESP_LOGI(TAG, "BSEC subscription succesful");
else {
ESP_LOGE(TAG, "BSEC subscription error");
rc = 0;
goto finish;
}
} else {
rc = checkIaqSensorStatus();
} else
ESP_LOGE(TAG, "I2c bus busy - BME680 initialization error");
rc = 0;
goto finish;
}
#elif defined HAS_BME280
bool status;
// block i2c bus access
if (I2C_MUTEX_LOCK()) {
status = bme.begin(BME280_ADDR);
if (!status) {
ESP_LOGE(TAG, "BME280 sensor not found");
rc = 0;
goto finish;
}
ESP_LOGI(TAG, "BME280 sensor found and initialized");
} else {
rc = bme.begin(BME280_ADDR);
} else
ESP_LOGE(TAG, "I2c bus busy - BME280 initialization error");
rc = 0;
goto finish;
}
#elif defined HAS_BMP180
bool status;
// block i2c bus access
if (I2C_MUTEX_LOCK()) {
// Wire.begin(21, 22);
status = bmp.begin();
if (!status) {
ESP_LOGE(TAG, "BMP180 sensor not found");
rc = 0;
goto finish;
}
ESP_LOGI(TAG, "BMP180 sensor found and initialized");
} else {
rc = bmp.begin();
} else
ESP_LOGE(TAG, "I2c bus busy - BMP180 initialization error");
rc = 0;
goto finish;
}
#endif
finish:
I2C_MUTEX_UNLOCK(); // release i2c bus access
if (rc)
bmecycler.attach(BMECYCLE, setBMEIRQ);
bmecycler.attach(BMECYCLE, setBMEIRQ); // start cyclic data transmit
return rc;
} // bme_init()
+4
View File
@@ -5,6 +5,10 @@
// (c) by Kaspar Metz
// modified for use in the Paxcounter by AQ
#if (COUNT_ENS) && !(BLECOUNTER)
#warning ENS-Counter needs Bluetooth, but Bluetooth compile option is disabled
#endif
#if (COUNT_ENS)
// Local logging tag
+7 -13
View File
@@ -14,22 +14,15 @@ extern boolean isSDS011Active;
#endif
void setCyclicIRQ() {
xTaskNotifyFromISR(irqHandlerTask, CYCLIC_IRQ, eSetBits, NULL);
xTaskNotify(irqHandlerTask, CYCLIC_IRQ, eSetBits);
}
// do all housekeeping
void doHousekeeping() {
// check if update mode trigger switch was set
if (RTC_runmode == RUNMODE_UPDATE) {
// check battery status if we can before doing ota
if (batt_sufficient()) {
do_reset(true); // warmstart to runmode update
} else {
ESP_LOGE(TAG, "Battery level %d%% is too low for OTA", batt_level);
RTC_runmode = RUNMODE_NORMAL; // keep running in normal mode
}
}
// check if update mode trigger switch was set by rcommand
if (RTC_runmode == RUNMODE_UPDATE)
do_reset(true);
// heap and task storage debugging
ESP_LOGD(TAG, "Heap: Free:%d, Min:%d, Size:%d, Alloc:%d, StackHWM:%d",
@@ -41,6 +34,8 @@ void doHousekeeping() {
ESP_LOGD(TAG, "MACprocessor %d bytes left | Taskstate = %d",
uxTaskGetStackHighWaterMark(macProcessTask),
eTaskGetState(macProcessTask));
ESP_LOGD(TAG, "Rcommand interpreter %d bytes left | Taskstate = %d",
uxTaskGetStackHighWaterMark(rcmdTask), eTaskGetState(rcmdTask));
#if (HAS_LORA)
ESP_LOGD(TAG, "LMiCtask %d bytes left | Taskstate = %d",
uxTaskGetStackHighWaterMark(lmicTask), eTaskGetState(lmicTask));
@@ -104,7 +99,6 @@ void doHousekeeping() {
"free heap = %d bytes)",
ESP.getMinFreeHeap(), ESP.getFreeHeap());
reset_counters(); // clear macs container and reset all counters
get_salt(); // get new salt for salting hashes
if (ESP.getMinFreeHeap() <= MEM_LOW) // check again
do_reset(true); // memory leak, reset device
@@ -115,7 +109,6 @@ void doHousekeeping() {
if (ESP.getMinFreePsram() <= MEM_LOW) {
ESP_LOGI(TAG, "PSRAM full, counter cleared");
reset_counters(); // clear macs container and reset all counters
get_salt(); // get new salt for salting hashes
if (ESP.getMinFreePsram() <= MEM_LOW) // check again
do_reset(true); // memory leak, reset device
@@ -147,6 +140,7 @@ void reset_counters() {
macs.clear(); // clear all macs container
macs_wifi = 0;
macs_ble = 0;
renew_salt(); // get new salt
#ifdef HAS_DISPLAY
dp_plotCurve(0, true);
#endif
+3 -3
View File
@@ -345,10 +345,10 @@ void dp_drawPage(time_t t, bool nextpage) {
#if (HAS_LORA)
// LMiC event display
dp_printf("%-16s", lmic_event_msg);
dp_printf("%-16s ", lmic_event_msg);
// LORA datarate, display inverse if ADR disabled
dp_setFont(MY_FONT_SMALL, !cfg.adrmode);
dp_printf(" %-4s", getSfName(updr2rps(LMIC.datarate)));
dp_printf("%-4s", getSfName(updr2rps(LMIC.datarate)));
dp_setFont(MY_FONT_SMALL, 0);
dp_println();
#endif // HAS_LORA
@@ -400,7 +400,7 @@ void dp_drawPage(time_t t, bool nextpage) {
gps.location.lat());
// line 6-7: GPS longitude
dp_printf("%c%07.4f", gps.location.rawLat().negative ? 'W' : 'E',
dp_printf("%c%07.4f", gps.location.rawLng().negative ? 'W' : 'E',
gps.location.lng());
} else {
+12 -19
View File
@@ -30,34 +30,27 @@ static uint16_t nmea_txDelay_ms = 0;
// initialize and configure GPS
int gps_init(void) {
int ret = 1;
if (!gps_config()) {
ESP_LOGE(TAG, "GPS chip initializiation error");
return 0;
}
#ifdef GPS_SERIAL
ESP_LOGI(TAG, "Opening serial GPS");
GPS_Serial.begin(GPS_SERIAL);
ESP_LOGI(TAG, "Using serial GPS");
#elif defined GPS_I2C
ESP_LOGI(TAG, "Opening I2C GPS");
Wire.begin(GPS_I2C, 400000); // I2C connect to GPS device with 400 KHz
Wire.beginTransmission(GPS_ADDR);
Wire.write(0x00); // dummy write
ret = Wire.endTransmission(); // check if chip is seen on i2c bus
if (ret) {
ESP_LOGE(TAG,
"Quectel L76 GPS chip not found on i2c bus, bus error %d. "
"Stopping GPS-Task.",
ret);
ret = 0;
} else {
Wire.write(0x00); // dummy write
if (Wire.endTransmission()) {
ESP_LOGE(TAG, "Quectel L76 GPS chip not found");
return 0;
} else
ESP_LOGI(TAG, "Quectel L76 GPS chip found");
}
#endif
return ret;
return 1;
} // gps_init()
// detect gps chipset type and configure it with device specific settings
@@ -109,7 +102,7 @@ time_t get_gpstime(uint16_t *msec) {
#endif
// did we get a current date & time?
if (gpstime.isValid() && gpsday.isValid()) {
if (gpstime.isValid()) {
time_t t = 0;
tmElements_t tm;
@@ -126,8 +119,8 @@ time_t get_gpstime(uint16_t *msec) {
tm.Year = CalendarYrToTm(atoi(gpsyear.value())); // year offset from 1970
t = makeTime(tm);
// ESP_LOGD(TAG, "GPS time/date = %2d:%2d:%2d / %2d.%2d.%2d", tm.Hour,
// tm.Minute, tm.Second, tm.Day, tm.Month, tm.Year + 1970);
ESP_LOGD(TAG, "GPS time/date = %02d:%02d:%02d / %02d.%02d.%2d", tm.Hour,
tm.Minute, tm.Second, tm.Day, tm.Month, tm.Year + 1970);
// add protocol delay with millisecond precision
t += delay_ms / 1000 - 1; // whole seconds
@@ -188,4 +181,4 @@ void gps_loop(void *pvParameters) {
} // gps_loop()
#endif // HAS_GPS
#endif // HAS_GPS
-1
View File
@@ -10,7 +10,6 @@
// Hardware related definitions for Pycom LoPy4 Board
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
#define LORA_RST LMIC_UNUSED_PIN // reset pin of lora chip is not wired von LoPy4
//#defin HAS_SPI 1 // comment out if device shall not send data via SPI
// pin definitions for local wired SPI slave interface
+58
View File
@@ -0,0 +1,58 @@
// clang-format off
// upload_speed 1500000
// board pico32
#ifndef _TTGOTWRISTBAND_H
#define _TTGOTWRISTBAND_H
#include <stdint.h>
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
#define HAS_DISPLAY 2 // TFT-LCD, support work in progess, not ready yet
#define MY_DISPLAY_FLIP 1 // use if display is rotated
#define HAS_LED NOT_A_PIN // no on board LED (?)
#define HAS_BUTTON (33) // on board button A
// power management settings
#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
#define BAT_VOLTAGE_DIVIDER 2.605f // voltage divider
// Display Settings
#define MY_DISPLAY_WIDTH 80
#define MY_DISPLAY_HEIGHT 160
#define MY_DISPLAY_INVERT 1
// setting for TTGO T-display
#define USER_SETUP_LOADED 1
#define ST7735_DRIVER 1
#define CGRAM_OFFSET
#define TFT_MISO -1
#define TFT_MOSI GPIO_NUM_19 // SPI
#define TFT_SCLK GPIO_NUM_18 // SPI
#define TFT_CS GPIO_NUM_5 // Chip select control
#define TFT_DC GPIO_NUM_23 // Data Command control
#define TFT_RST GPIO_NUM_26 // Reset
#define TFT_BL GPIO_NUM_27 // LED back-light
#define TFT_BACKLIGHT_ON 1
#define ST7735_GREENTAB160x80
#define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
#define SMOOTH_FONT
#define SPI_FREQUENCY 27000000
#define SPI_READ_FREQUENCY 6000000
#endif
+5 -47
View File
@@ -36,52 +36,10 @@
#include "hash.h"
uint32_t IRAM_ATTR rokkit(const char *data, int len) {
uint32_t hash, tmp;
int rem;
#ifdef ROKKIT_ENABLE_8BIT_OPTIMIZATIONS
#undef ROKKIT_ENABLE_8BIT_OPTIMIZATIONS
#endif
if (len <= 0 || data == 0)
return 0;
hash = len;
rem = len & 3;
len >>= 2;
/* Main loop */
while (len > 0) {
hash += *((uint16_t *)data);
tmp = (*((uint16_t *)(data + 2)) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * 2;
hash += hash >> 11;
len--;
}
/* Handle end cases */
switch (rem) {
case 3:
hash += *((uint16_t *)data);
hash ^= hash << 16;
hash ^= ((signed char)data[2]) << 18;
hash += hash >> 11;
break;
case 2:
hash += *((uint16_t *)data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1:
hash += (signed char)*data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
uint32_t IRAM_ATTR hash(const char *data, int len) {
return rokkit(data, len);
}
+2 -2
View File
@@ -84,7 +84,7 @@ void i2c_scan(void) {
}
// mutexed functions for i2c r/w access
uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
int i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
if (I2C_MUTEX_LOCK()) {
uint8_t ret = 0;
@@ -112,7 +112,7 @@ uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
}
}
uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
int i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
if (I2C_MUTEX_LOCK()) {
uint8_t ret = 0;
+4 -3
View File
@@ -18,9 +18,10 @@
// use interrupts only if LORA_IRQ and LORA_DIO are connected to interrupt
// capable and separate GPIO pins on your board, if not don't enable
#if (LORA_IRQ) != (LORA_IO1)
#define LMIC_USE_INTERRUPTS 1
#endif
// note: this feature can't be used on ESP32 unless PR #556 of MCCI LMIC was merged
//#if (LORA_IRQ) != (LORA_IO1)
//#define LMIC_USE_INTERRUPTS 1
//#endif
// avoid lmic warning if we don't configure radio in case we haven't one
#if !(defined(CFG_sx1272_radio) || defined(CFG_sx1276_radio))
+5 -9
View File
@@ -19,7 +19,7 @@ RTC_DATA_ATTR lmic_t RTC_LMIC;
#endif
#endif
QueueHandle_t LoraSendQueue;
static QueueHandle_t LoraSendQueue;
TaskHandle_t lmicTask = NULL, lorasendTask = NULL;
class MyHalConfig_t : public Arduino_LMIC::HalConfiguration_t {
@@ -284,14 +284,10 @@ esp_err_t lmic_init(void) {
// Pass OTA parameters to LMIC_setSession
#else
// load saved session from RTC, if we have one
if (RTC_runmode == RUNMODE_WAKEUP) {
if (RTC_runmode == RUNMODE_WAKEUP)
LoadLMICFromRTC();
}
// otherwise start join procedure if not already joined
else {
if (!LMIC_startJoining())
ESP_LOGI(TAG, "Already joined");
}
if (!LMIC_startJoining())
ESP_LOGI(TAG, "Already joined");
#endif
// start lmic loop task
@@ -545,7 +541,7 @@ void SaveLMICToRTC(int deepsleep_sec) {
unsigned long now = millis();
// EU Like Bands
#if defined(CFG_LMIC_EU_like)
#if CFG_LMIC_EU_like
for (int i = 0; i < MAX_BANDS; i++) {
ostime_t correctedAvail =
RTC_LMIC.bands[i].avail -
+25 -29
View File
@@ -6,13 +6,14 @@
// Local logging tag
static const char TAG[] = __FILE__;
QueueHandle_t MacQueue;
static QueueHandle_t MacQueue;
TaskHandle_t macProcessTask;
uint16_t salt = 0;
static uint32_t salt = renew_salt();
uint16_t get_salt(void) {
salt = (uint16_t)random(65536); // get new 16bit random for salting hashes
uint32_t renew_salt(void) {
salt = esp_random();
ESP_LOGV(TAG, "new salt = %04X", salt);
return salt;
}
@@ -101,8 +102,9 @@ void IRAM_ATTR mac_add(uint8_t *paddr, int8_t rssi, snifftype_t sniff_type) {
uint16_t mac_analyze(MacBuffer_t MacBuffer) {
if (salt == 0) // ensure we have salt (appears after radio is turned on)
return 0;
uint32_t *mac; // pointer to shortened 4 byte MAC
uint32_t saltedmac;
uint16_t hashedmac;
if ((cfg.rssilimit) &&
(MacBuffer.rssi < cfg.rssilimit)) { // rssi is negative value
@@ -117,18 +119,13 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
int8_t beaconID = isBeacon(macConvert(MacBuffer.mac));
if (beaconID >= 0) {
ESP_LOGI(TAG, "Beacon ID#%d detected", beaconID);
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
blink_LED(COLOR_WHITE, 2000);
#endif
payload.reset();
payload.addAlarm(MacBuffer.rssi, beaconID);
SendPayload(BEACONPORT);
}
};
char buff[10]; // temporary buffer for printf
uint32_t *mac; // temporary buffer for shortened MAC
// only last 3 MAC Address bytes are used for MAC address anonymization
// but since it's uint32 we take 4 bytes to avoid 1st value to be 0.
// this gets MAC in msb (= reverse) order, but doesn't matter for hashing it.
@@ -138,11 +135,15 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
// and increment counter on display
// https://en.wikipedia.org/wiki/MAC_Address_Anonymization
snprintf(buff, sizeof(buff), "%08X",
*mac + (uint32_t)salt); // convert unsigned 32-bit salted MAC
// to 8 digit hex string
uint16_t hashedmac = rokkit(&buff[3], 5); // hash MAC 8 digit -> 5 digit
auto newmac = macs.insert(hashedmac); // add hashed MAC, if new unique
// reversed 4 byte MAC added to current salt
saltedmac = *mac + salt;
// hashed 4 byte MAC
// to save RAM, we use only lower 2 bytes of hash, since collisions don't
// matter in our use case
hashedmac = hash((const char *)&saltedmac, 4);
auto newmac = macs.insert(hashedmac); // add hashed MAC, if new unique
bool added =
newmac.second ? true : false; // true if hashed MAC is unique in container
@@ -153,37 +154,30 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
case MAC_SNIFF_WIFI:
macs_wifi++; // increment Wifi MACs counter
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
blink_LED(COLOR_GREEN, 50);
#endif
break;
#if (BLECOUNTER)
case MAC_SNIFF_BLE:
macs_ble++; // increment BLE Macs counter
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
blink_LED(COLOR_MAGENTA, 50);
#endif
break;
#if (COUNT_ENS)
case MAC_SNIFF_BLE_ENS:
macs_ble++; // increment BLE Macs counter
cwa_mac_add(hashedmac); // process ENS beacon
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
blink_LED(COLOR_WHITE, 50);
#endif
break;
#endif // COUNT_ENS
#endif // BLECOUNTER
#endif
default:
break;
} // switch
} // added
// Log scan result
ESP_LOGV(TAG,
"%s %s RSSI %ddBi -> salted MAC %s -> Hash %04X -> WiFi:%d "
"%s %s RSSI %ddBi -> MAC %0x:%0x:%0x:%0x:%0x:%0x -> salted %04X"
" -> hashed %04X -> WiFi:%d "
"BLTH:%d "
#if (COUNT_ENS)
"(CWA:%d)"
@@ -191,7 +185,9 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
"-> %d Bytes left",
added ? "new " : "known",
MacBuffer.sniff_type == MAC_SNIFF_WIFI ? "WiFi" : "BLTH",
MacBuffer.rssi, buff, hashedmac, macs_wifi, macs_ble,
MacBuffer.rssi, MacBuffer.mac[0], MacBuffer.mac[1], MacBuffer.mac[2],
MacBuffer.mac[3], MacBuffer.mac[4], MacBuffer.mac[5], saltedmac,
hashedmac, macs_wifi, macs_ble,
#if (COUNT_ENS)
cwa_report(),
#endif
+16 -7
View File
@@ -29,16 +29,17 @@ Task Core Prio Purpose
-------------------------------------------------------------------------------
ledloop 0 3 blinks LEDs
spiloop 0 2 reads/writes data on spi interface
mqttloop 0 2 reads/writes data on ETH interface
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
lmictask 1 2 MCCI LMiC LORAWAN stack
clockloop 1 4 generates realtime telegrams for external clock
mqttloop 1 2 reads/writes data on ETH interface
timesync_proc 1 3 processes realtime time sync requests
irqhandler 1 2 cyclic tasks (i.e. displayrefresh) triggered by timers
gpsloop 1 1 reads data from GPS via serial or i2c
lorasendtask 1 1 feeds data from lora sendqueue to lmcic
macprocess 1 1 analyzes sniffed MACs
macprocess 1 1 MAC analyzer loop
rmcd_process 1 1 Remote command interpreter loop
IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator
Low priority numbers denote low priority tasks.
@@ -60,8 +61,10 @@ irqHandlerTask (Core 1), see irqhandler.cpp
fired by hardware
DisplayIRQ -> esp32 timer 0
ButtonIRQ -> external gpio
PMUIRQ -> PMU chip gpio
CLOCKIRQ -> esp32 timer 1 or external GPIO (RTC_INT or GPS_INT)
MatrixDisplayIRQ-> esp32 timer 3
ButtonIRQ -> external GPIO
PMUIRQ -> PMU chip GPIO
fired by software (Ticker.h)
TIMESYNC_IRQ -> setTimeSyncIRQ()
@@ -100,7 +103,7 @@ timesource_t timeSource = _unsynced;
// container holding unique MAC address hashes with Memory Alloctor using PSRAM,
// if present
std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
DRAM_ATTR std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
// initialize payload encoder
PayloadConvert payload(PAYLOAD_BUFFER_SIZE);
@@ -291,6 +294,10 @@ void setup() {
ESP_LOGI(TAG, "Starting MAC processor...");
macQueueInit();
// start rcommand processing task
ESP_LOGI(TAG, "Starting rcommand interpreter...");
rcmd_init();
// start BLE scan callback if BLE function is enabled in NVRAM configuration
// or remove bluetooth stack from RAM, if option bluetooth is not compiled
#if (BLECOUNTER)
@@ -428,7 +435,7 @@ void setup() {
// initialize salt value using esp_random() called by random() in
// arduino-esp32 core. Note: do this *after* wifi has started, since
// function gets it's seed from RF noise
get_salt(); // get new 16bit for salting hashes
reset_counters();
// start state machine
ESP_LOGI(TAG, "Starting Interrupt Handler...");
@@ -451,8 +458,10 @@ void setup() {
#endif
if (bme_init())
ESP_LOGI(TAG, "BME sensor initialized");
else
else {
ESP_LOGE(TAG, "BME sensor could not be initialized");
cfg.payloadmask &= ~MEMS_DATA; // switch off transmit of BME data
}
#endif
// starting timers and interrupts
+47 -60
View File
@@ -4,7 +4,7 @@
static const char TAG[] = __FILE__;
QueueHandle_t MQTTSendQueue;
static QueueHandle_t MQTTSendQueue;
TaskHandle_t mqttTask;
Ticker mqttTimer;
@@ -12,6 +12,7 @@ WiFiClient netClient;
MQTTClient mqttClient;
void mqtt_deinit(void) {
mqttClient.unsubscribe(MQTT_INTOPIC);
mqttClient.onMessageAdvanced(NULL);
mqttClient.disconnect();
vTaskDelete(mqttTask);
@@ -19,12 +20,10 @@ void mqtt_deinit(void) {
esp_err_t mqtt_init(void) {
// setup network connection
WiFi.onEvent(NetworkEvent);
// setup network connection and MQTT client
ETH.begin();
// setup mqtt client
mqttClient.begin(MQTT_SERVER, MQTT_PORT, netClient);
mqttClient.setKeepAlive(MQTT_KEEPALIVE);
mqttClient.onMessageAdvanced(mqtt_callback);
_ASSERT(SEND_QUEUE_SIZE > 0);
@@ -37,15 +36,20 @@ esp_err_t mqtt_init(void) {
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
ESP_LOGI(TAG, "Starting MQTTloop...");
xTaskCreate(mqtt_client_task, "mqttloop", 4096, (void *)NULL, 1, &mqttTask);
xTaskCreatePinnedToCore(mqtt_client_task, "mqttloop", 4096, (void *)NULL, 1,
&mqttTask, 1);
return ESP_OK;
}
int mqtt_connect(const char *my_host, const uint16_t my_port) {
IPAddress mqtt_server_ip;
uint8_t mac[6];
char clientId[20];
static String clientId = "paxcounter-" + ETH.macAddress();
// hash 6 byte MAC to 4 byte hash
esp_eth_get_mac(mac);
const uint32_t hashedmac = hash((const char *)mac, 6);
snprintf(clientId, 20, "paxcounter_%08x", hashedmac);
ESP_LOGI(TAG, "MQTT name is %s", MQTT_CLIENTNAME);
@@ -75,41 +79,6 @@ int mqtt_connect(const char *my_host, const uint16_t my_port) {
return 0;
}
void NetworkEvent(WiFiEvent_t event) {
switch (event) {
case SYSTEM_EVENT_ETH_START:
case SYSTEM_EVENT_STA_START:
ESP_LOGI(TAG, "Network link layer started");
// ETH.setHostname(ETH.macAddress().c_str());
break;
case SYSTEM_EVENT_ETH_STOP:
case SYSTEM_EVENT_STA_STOP:
ESP_LOGI(TAG, "Network link layer stopped");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
case SYSTEM_EVENT_STA_CONNECTED:
ESP_LOGI(TAG, "Network link connected");
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "Network link disconnected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
ESP_LOGI(TAG, "IP: %s", ETH.localIP().toString().c_str());
ESP_LOGI(TAG, "Link Speed: %d Mbps %s", ETH.linkSpeed(),
ETH.fullDuplex() ? "full duplex" : "half duplex");
mqtt_connect(MQTT_SERVER, MQTT_PORT);
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "IP: %s", WiFi.localIP().toString().c_str());
mqtt_connect(MQTT_SERVER, MQTT_PORT);
break;
default:
break;
}
}
void mqtt_client_task(void *param) {
MessageBuffer_t msg;
@@ -128,21 +97,28 @@ void mqtt_client_task(void *param) {
MQTT_KEEPALIVE * 1000 / portTICK_PERIOD_MS) != pdTRUE)
continue;
// send data to mqtt server
char buffer[PAYLOAD_BUFFER_SIZE + 3];
snprintf(buffer, msg.MessageSize + 3, "%u/%s", msg.MessagePort,
msg.Message);
// prepare mqtt topic
char topic[16];
snprintf(topic, 16, "%s/%u", MQTT_OUTTOPIC, msg.MessagePort);
size_t out_len = 0;
if (mqttClient.publish(MQTT_OUTTOPIC, buffer)) {
ESP_LOGI(TAG, "%d byte(s) sent to MQTT server", msg.MessageSize + 2);
// delete sent item from queue
// get length of base64 encoded message
mbedtls_base64_encode(NULL, 0, &out_len, (unsigned char *)msg.Message,
msg.MessageSize);
// base64 encode the message
unsigned char encoded[out_len];
mbedtls_base64_encode(encoded, out_len, &out_len,
(unsigned char *)msg.Message, msg.MessageSize);
// send encoded message to mqtt server and delete it from queue
if (mqttClient.publish(topic, (const char *)encoded, out_len)) {
ESP_LOGD(TAG, "%u bytes sent to MQTT server", out_len);
xQueueReceive(MQTTSendQueue, &msg, (TickType_t)0);
} else
ESP_LOGD(TAG, "Couldn't sent message to MQTT server");
} else {
// attempt to reconnect to MQTT server
ESP_LOGD(TAG, "MQTT error = %d / rc = %d", mqttClient.lastError(),
mqttClient.returnCode());
ESP_LOGD(TAG, "MQTT client reconnecting...");
delay(MQTT_RETRYSEC * 1000);
mqtt_connect(MQTT_SERVER, MQTT_PORT);
@@ -150,16 +126,27 @@ void mqtt_client_task(void *param) {
} // while (1)
}
void mqtt_enqueuedata(MessageBuffer_t *message) {
// enqueue message in MQTT send queue
if (xQueueSendToBack(MQTTSendQueue, (void *)message, (TickType_t)0) != pdTRUE)
ESP_LOGW(TAG, "MQTT sendqueue is full");
// process incoming MQTT messages
void mqtt_callback(MQTTClient *client, char *topic, char *payload, int length) {
if (strcmp(topic, MQTT_INTOPIC) == 0) {
// get length of base64 encoded message
size_t out_len = 0;
mbedtls_base64_decode(NULL, 0, &out_len, (unsigned char *)payload, length);
// decode the base64 message
unsigned char decoded[out_len];
mbedtls_base64_decode(decoded, out_len, &out_len, (unsigned char *)payload,
length);
rcommand(decoded, out_len);
}
}
void mqtt_callback(MQTTClient *client, char topic[], char payload[],
int length) {
if (strcmp(topic, MQTT_INTOPIC) == 0)
rcommand((const uint8_t *)payload, (const uint8_t)length);
// enqueue outgoing messages in MQTT send queue
void mqtt_enqueuedata(MessageBuffer_t *message) {
if (xQueueSendToBack(MQTTSendQueue, (void *)message, (TickType_t)0) != pdTRUE)
ESP_LOGW(TAG, "MQTT sendqueue is full");
}
void mqtt_queuereset(void) { xQueueReset(MQTTSendQueue); }
+12
View File
@@ -121,3 +121,15 @@
#define CAYENNE_DEVICECONFIG 11 // device period configuration
#define CAYENNE_SENSORREAD 13 // sensor period configuration
#define CAYENNE_SENSORENABLE 14 // sensor enable configuration
// MQTT settings, only needed if MQTT is used (#define HAS_MQTT in board hal file)
#define MQTT_ETHERNET 0 // select PHY: set 0 for Wifi, 1 for ethernet
#define MQTT_INTOPIC "paxin"
#define MQTT_OUTTOPIC "paxout"
#define MQTT_PORT 1883
#define MQTT_SERVER "public.cloud.shiftr.io"
#define MQTT_USER "public"
#define MQTT_PASSWD "public"
#define MQTT_RETRYSEC 20 // retry reconnect every 20 seconds
#define MQTT_KEEPALIVE 10 // keep alive interval in seconds
//#define MQTT_CLIENTNAME "my_paxcounter" // generated by default
+21 -7
View File
@@ -46,6 +46,14 @@ void AXP192_powerevent_IRQ(void) {
ESP_LOGI(TAG, "Battery high temperature.");
if (pmu.isBattTempHighIRQ())
ESP_LOGI(TAG, "Battery low temperature.");
if (pmu.isLowVoltageLevel1IRQ()) {
ESP_LOGI(TAG, "Battery has reached voltage level 1.");
pmu.setChgLEDMode(AXP20X_LED_BLINK_4HZ);
}
if (pmu.isLowVoltageLevel2IRQ()) {
ESP_LOGI(TAG, "Battery has reached voltage level 2.");
pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ);
}
// short press -> esp32 deep sleep mode, can be exited by pressing user button
if (pmu.isPEKShortPressIRQ()) {
@@ -129,10 +137,15 @@ void AXP192_init(void) {
pmu.setLDO2Voltage(3300); // LORA VDD 3v3
pmu.setLDO3Voltage(3300); // GPS VDD 3v3
// configure voltage warning levels
pmu.setVWarningLevel1(3600);
pmu.setVWarningLevel2(3800);
pmu.setPowerDownVoltage(3300);
// configure PEK button settings
pmu.setTimeOutShutdown(false); // forced shutdown by PEK enabled
pmu.setShutdownTime(
AXP_POWER_OFF_TIME_65); // 6 sec button press for shutdown
AXP_POWER_OFF_TIME_6S); // 6 sec button press for shutdown
pmu.setlongPressTime(
AXP_LONGPRESS_TIME_1S5); // 1.5 sec button press for long press
pmu.setStartupTime(
@@ -158,9 +171,9 @@ void AXP192_init(void) {
#endif // PMU_INT
// set charging parameterss according to user settings if we have (see power.h)
#ifdef PMU_CHARGE_CURRENT
pmu.setChargeControlCur(PMU_CHARGE_CURRENT);
pmu.setChargingTargetVoltage(PMU_CHARGE_CUTOFF);
#ifdef PMU_CHG_CURRENT
pmu.setChargeControlCur(PMU_CHG_CURRENT);
pmu.setChargingTargetVoltage(PMU_CHG_CUTOFF);
pmu.enableChargeing(true);
#endif
@@ -251,10 +264,11 @@ uint8_t read_battlevel(mapFn_t mapFunction) {
bool batt_sufficient() {
#if (defined HAS_PMU || defined BAT_MEASURE_ADC || defined HAS_IP5306)
return (batt_level > OTA_MIN_BATT);
#else
return true; // we don't know batt level
if (batt_level) // we have a battery voltage
return (batt_level > OTA_MIN_BATT);
else
#endif
return true; // we don't know batt level
}
#ifdef HAS_IP5306
+102 -37
View File
@@ -5,8 +5,8 @@
// Local logging tag
static const char TAG[] = __FILE__;
// global variable indicating if rcommand() is executing
bool rcmd_busy = false;
static QueueHandle_t RcmdQueue;
TaskHandle_t rcmdTask;
// set of functions that can be triggered by remote commands
void set_reset(uint8_t val[]) {
@@ -18,7 +18,6 @@ void set_reset(uint8_t val[]) {
case 1: // reset MAC counter
ESP_LOGI(TAG, "Remote command: reset MAC counter");
reset_counters(); // clear macs
get_salt(); // get new salt
break;
case 2: // reset device to factory settings
ESP_LOGI(TAG, "Remote command: reset device to factory settings");
@@ -35,7 +34,11 @@ void set_reset(uint8_t val[]) {
case 9: // reset and ask for software update via Wifi OTA
ESP_LOGI(TAG, "Remote command: software update via Wifi");
#if (USE_OTA)
RTC_runmode = RUNMODE_UPDATE;
// check power status before scheduling ota update
if (batt_sufficient())
RTC_runmode = RUNMODE_UPDATE;
else
ESP_LOGE(TAG, "Battery level %d%% is too low for OTA", batt_level);
#endif // USE_OTA
break;
@@ -115,7 +118,6 @@ void set_countmode(uint8_t val[]) {
return;
}
reset_counters(); // clear macs
get_salt(); // get new salt
}
void set_screensaver(uint8_t val[]) {
@@ -164,7 +166,7 @@ void set_payloadmask(uint8_t val[]) {
void set_sensor(uint8_t val[]) {
#if (HAS_SENSORS)
switch (val[0]) { // check if valid sensor number 1...4
switch (val[0]) { // check if valid sensor number 1..3
case 1:
case 2:
case 3:
@@ -367,41 +369,49 @@ void set_enscount(uint8_t val[]) {
cfg.payloadmask &= ~SENSOR1_DATA;
}
void set_loadconfig(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: load config from NVRAM");
loadConfig();
};
void set_saveconfig(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: save config to NVRAM");
saveConfig(false);
};
// assign previously defined functions to set of numeric remote commands
// format: opcode, function, #bytes params,
// flag (true = do make settings persistent / false = don't)
//
// format: {opcode, function, number of function arguments}
static const 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_loradr, 1, true}, {0x06, set_lorapower, 1, true},
{0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 1, true},
{0x09, set_reset, 1, false}, {0x0a, set_sendcycle, 1, true},
{0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true},
{0x0d, set_macfilter, 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}, {0x14, set_payloadmask, 1, true},
{0x15, set_bme, 1, true}, {0x16, set_batt, 1, true},
{0x17, set_wifiscan, 1, true}, {0x18, set_enscount, 1, true},
{0x19, set_sleepcycle, 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}};
{0x01, set_rssi, 1}, {0x02, set_countmode, 1},
{0x03, set_gps, 1}, {0x04, set_display, 1},
{0x05, set_loradr, 1}, {0x06, set_lorapower, 1},
{0x07, set_loraadr, 1}, {0x08, set_screensaver, 1},
{0x09, set_reset, 1}, {0x0a, set_sendcycle, 1},
{0x0b, set_wifichancycle, 1}, {0x0c, set_blescantime, 1},
{0x0d, set_macfilter, 1}, {0x0e, set_blescan, 1},
{0x0f, set_wifiant, 1}, {0x10, set_rgblum, 1},
{0x11, set_monitor, 1}, {0x12, set_beacon, 7},
{0x13, set_sensor, 2}, {0x14, set_payloadmask, 1},
{0x15, set_bme, 1}, {0x16, set_batt, 1},
{0x17, set_wifiscan, 1}, {0x18, set_enscount, 1},
{0x19, set_sleepcycle, 1}, {0x20, set_loadconfig, 0},
{0x21, set_saveconfig, 0}, {0x80, get_config, 0},
{0x81, get_status, 0}, {0x83, get_batt, 0},
{0x84, get_gps, 0}, {0x85, get_bme, 0},
{0x86, get_time, 0}, {0x87, set_time, 0},
{0x99, set_flush, 0}};
static const uint8_t cmdtablesize =
sizeof(table) / sizeof(table[0]); // number of commands in command table
// check and execute remote command
void rcommand(const uint8_t cmd[], const uint8_t cmdlength) {
void rcmd_execute(const uint8_t cmd[], const uint8_t cmdlength) {
if (cmdlength == 0)
return;
uint8_t foundcmd[cmdlength], cursor = 0;
bool storeflag = false;
rcmd_busy = true;
while (cursor < cmdlength) {
@@ -413,8 +423,6 @@ void rcommand(const uint8_t cmd[], const uint8_t cmdlength) {
memmove(foundcmd, cmd + cursor,
table[i].params); // strip opcode from cmd array
cursor += table[i].params;
if (table[i].store) // ceck if function needs to store configuration
storeflag = true;
table[i].func(
foundcmd); // execute assigned function with given parameters
} else
@@ -422,18 +430,75 @@ void rcommand(const uint8_t cmd[], const uint8_t cmdlength) {
"Remote command x%02X called with missing parameter(s), "
"skipped",
table[i].opcode);
break; // command found -> exit table lookup loop
} // end of command validation
} // end of command table lookup loop
break; // command found -> exit table lookup loop
} // end of command validation
} // end of command table lookup loop
if (i < 0) { // command not found -> exit parser
ESP_LOGI(TAG, "Unknown remote command x%02X, ignored", cmd[cursor]);
break;
}
} // command parsing loop
if (storeflag)
saveConfig();
} // rcmd_execute()
rcmd_busy = false;
// remote command processing task
void rcmd_process(void *pvParameters) {
_ASSERT((uint32_t)pvParameters == 1); // FreeRTOS check
RcmdBuffer_t RcmdBuffer;
while (1) {
// fetch next or wait for incoming rcommand from queue
if (xQueueReceive(RcmdQueue, &RcmdBuffer, portMAX_DELAY) != pdTRUE) {
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
continue;
}
rcmd_execute(RcmdBuffer.cmd, RcmdBuffer.cmdLen);
}
delay(2); // yield to CPU
} // rcmd_process()
// enqueue remote command
void IRAM_ATTR rcommand(const uint8_t *cmd, const size_t cmdlength) {
RcmdBuffer_t rcmd = {0};
rcmd.cmdLen = cmdlength;
memcpy(rcmd.cmd, cmd, cmdlength);
if (xQueueSendToBack(RcmdQueue, (void *)&rcmd, (TickType_t)0) != pdTRUE)
ESP_LOGW(TAG, "Remote command queue is full");
} // rcommand()
void rcmd_queuereset(void) { xQueueReset(RcmdQueue); }
uint32_t rcmd_queuewaiting(void) { return uxQueueMessagesWaiting(RcmdQueue); }
void rcmd_deinit(void) {
rcmd_queuereset();
vTaskDelete(rcmdTask);
}
esp_err_t rcmd_init(void) {
_ASSERT(RCMD_QUEUE_SIZE > 0);
RcmdQueue = xQueueCreate(RCMD_QUEUE_SIZE, sizeof(RcmdBuffer_t));
if (RcmdQueue == 0) {
ESP_LOGE(TAG, "Could not create rcommand send queue. Aborting.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "Rcommand send queue created, size %d Bytes",
RCMD_QUEUE_SIZE * sizeof(RcmdBuffer_t));
xTaskCreatePinnedToCore(rcmd_process, // task function
"rcmdloop", // name of task
3072, // stack size of task
(void *)1, // parameter of the task
1, // priority of the task
&rcmdTask, // task handle
1); // CPU core
return ESP_OK;
} // rcmd_init()
+45 -56
View File
@@ -9,7 +9,7 @@ static const char TAG[] = __FILE__;
#define uS_TO_S_FACTOR 1000000ULL
// variables keep its values after a wakeup from sleep
RTC_DATA_ATTR runmode_t RTC_runmode = RUNMODE_POWERCYCLE;
RTC_NOINIT_ATTR runmode_t RTC_runmode = RUNMODE_POWERCYCLE;
RTC_DATA_ATTR struct timeval RTC_sleep_start_time;
RTC_DATA_ATTR unsigned long long RTC_millis = 0;
timeval sleep_stop_time;
@@ -36,14 +36,19 @@ void do_after_reset(void) {
struct timeval sleep_stop_time;
uint64_t sleep_time_ms;
switch (esp_sleep_get_wakeup_cause()) {
case ESP_SLEEP_WAKEUP_EXT0: // Wakeup caused by external signal using RTC_IO
case ESP_SLEEP_WAKEUP_EXT1: // Wakeup caused by external signal using
// RTC_CNTL
case ESP_SLEEP_WAKEUP_TIMER: // Wakeup caused by timer
case ESP_SLEEP_WAKEUP_TOUCHPAD: // Wakeup caused by touchpad
case ESP_SLEEP_WAKEUP_ULP: // Wakeup caused by ULP program
switch (rtc_get_reset_reason(0)) {
case POWERON_RESET: // 0x01 Vbat power on reset
case RTCWDT_BROWN_OUT_RESET: // 0x0f Reset when the vdd voltage is not
// stable
RTC_runmode = RUNMODE_POWERCYCLE;
break;
case SW_CPU_RESET: // 0x0c Software reset CPU
// keep previous runmode (could be RUNMODE_UPDATE)
break;
case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core
// calculate time spent in deep sleep
gettimeofday(&sleep_stop_time, NULL);
sleep_time_ms =
@@ -51,48 +56,46 @@ void do_after_reset(void) {
(sleep_stop_time.tv_usec - RTC_sleep_start_time.tv_usec) / 1000;
ESP_LOGI(TAG, "Time spent in deep sleep: %d ms", sleep_time_ms);
RTC_millis += sleep_time_ms; // increment system monotonic time
RTC_runmode = RUNMODE_WAKEUP;
// set wakeup state, not if we have pending OTA update
if (RTC_runmode == RUNMODE_SLEEP)
RTC_runmode = RUNMODE_WAKEUP;
break;
case ESP_SLEEP_WAKEUP_ALL:
case ESP_SLEEP_WAKEUP_GPIO:
case ESP_SLEEP_WAKEUP_UART:
case ESP_SLEEP_WAKEUP_UNDEFINED:
case SW_RESET: // 0x03 Software reset digital core
case OWDT_RESET: // 0x04 Legacy watch dog reset digital core
case SDIO_RESET: // 0x06 Reset by SLC module, reset digital core
case TG0WDT_SYS_RESET: // 0x07 Timer Group0 Watch dog reset digital core
case TG1WDT_SYS_RESET: // 0x08 Timer Group1 Watch dog reset digital core
case RTCWDT_SYS_RESET: // 0x09 RTC Watch dog Reset digital core
case INTRUSION_RESET: // 0x0a Instrusion tested to reset CPU
case TGWDT_CPU_RESET: // 0x0b Time Group reset CPU
case RTCWDT_CPU_RESET: // 0x0d RTC Watch dog Reset CPU
case EXT_CPU_RESET: // 0x0e for APP CPU, reseted by PRO CPU
case RTCWDT_RTC_RESET: // 0x10 RTC Watch dog reset digital core and rtc mode
default:
// not a deep sleep reset
RTC_runmode = RUNMODE_POWERCYCLE;
break;
} // switch
}
ESP_LOGI(TAG, "Starting Software v%s, runmode %s", PROGVERSION,
runmode[RTC_runmode]);
}
void enter_deepsleep(const uint64_t wakeup_sec = 60,
gpio_num_t wakeup_gpio = GPIO_NUM_MAX) {
void enter_deepsleep(const uint64_t wakeup_sec, gpio_num_t wakeup_gpio) {
#if (HAS_LORA)
if (!LMIC.devaddr) {
ESP_LOGI(TAG, "Can't go to sleep while joining");
return;
}
#endif
ESP_LOGI(TAG, "Preparing to sleep...");
RTC_runmode = RUNMODE_SLEEP;
int i;
// validate wake up pin, if we have
if (!GPIO_IS_VALID_GPIO(wakeup_gpio))
wakeup_gpio = GPIO_NUM_MAX;
ESP_LOGI(TAG, "Preparing to sleep...");
RTC_runmode = RUNMODE_SLEEP;
// stop further enqueuing of senddata and MAC processing
sendTimer.detach();
// switch off radio
// switch off radio and other power consuming hardware
#if (WIFICOUNTER)
switch_wifi_sniffer(0);
#endif
@@ -100,6 +103,9 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
stop_BLEscan();
btStop();
#endif
#if (HAS_SDS011)
sds011_sleep(void);
#endif
// stop MAC processing
vTaskDelete(macProcessTask);
@@ -109,27 +115,22 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
// wait a while (max 100 sec) to clear send queues
ESP_LOGI(TAG, "Waiting until send queues are empty...");
for (i = 10; i > 0; i--) {
if (!allQueuesEmtpy())
vTaskDelay(pdMS_TO_TICKS(10000));
else
for (i = 100; i > 0; i--) {
if (allQueuesEmtpy())
break;
vTaskDelay(pdMS_TO_TICKS(1000));
}
if (i == 0)
goto Error;
// shutdown LMIC safely, waiting max 100 sec
// shutdown LMIC safely, waiting max 100 sec
#if (HAS_LORA)
ESP_LOGI(TAG, "Waiting until LMIC is idle...");
for (i = 10; i > 0; i--) {
for (i = 100; i > 0; i--) {
if ((LMIC.opmode & OP_TXRXPEND) ||
os_queryTimeCriticalJobs(sec2osticks(wakeup_sec)))
vTaskDelay(pdMS_TO_TICKS(10000));
vTaskDelay(pdMS_TO_TICKS(1000));
else
break;
}
if (i == 0)
goto Error;
#endif // (HAS_LORA)
// shutdown MQTT safely
@@ -142,17 +143,7 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
spi_deinit();
#endif
// wait until rcommands are all done
for (i = 10; i > 0; i--) {
if (rcmd_busy)
vTaskDelay(pdMS_TO_TICKS(1000));
else
break;
}
if (i == 0)
goto Error;
// save LMIC state to RTC RAM
// save LMIC state to RTC RAM
#if (HAS_LORA)
SaveLMICToRTC(wakeup_sec);
#endif // (HAS_LORA)
@@ -162,9 +153,11 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
dp_shutdown();
#endif
// reduce power if has PMU
// reduce power if has PMU or VEXT
#ifdef HAS_PMU
AXP192_power(pmu_power_sleep);
#elif EXT_POWER_SW
digitalWrite(EXT_POWER_SW, EXT_POWER_OFF);
#endif
// shutdown i2c bus
@@ -189,10 +182,6 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
RTC_millis += millis();
ESP_LOGI(TAG, "Going to sleep, good bye.");
esp_deep_sleep_start();
Error:
ESP_LOGE(TAG, "Can't go to sleep. Resetting.");
do_reset(true);
}
unsigned long long uptime() { return (RTC_millis + millis()); }
+4 -5
View File
@@ -4,7 +4,7 @@
Ticker sendTimer;
void setSendIRQ() {
xTaskNotifyFromISR(irqHandlerTask, SENDCYCLE_IRQ, eSetBits, NULL);
xTaskNotify(irqHandlerTask, SENDCYCLE_IRQ, eSetBits);
}
// put data to send in RTos Queues used for transmit over channels Lora and SPI
@@ -12,8 +12,7 @@ void SendPayload(uint8_t port) {
ESP_LOGD(TAG, "sending Payload for Port %d", port);
MessageBuffer_t
SendBuffer; // contains MessageSize, MessagePort, Message[]
MessageBuffer_t SendBuffer; // contains MessageSize, MessagePort, Message[]
SendBuffer.MessageSize = payload.getSize();
@@ -115,7 +114,6 @@ void sendData() {
// clear counter if not in cumulative counter mode
if (cfg.countermode != 1) {
reset_counters(); // clear macs container and reset all counters
get_salt(); // get new salt for salting hashes
ESP_LOGI(TAG, "Counter cleared");
}
#ifdef HAS_DISPLAY
@@ -191,6 +189,7 @@ void sendData() {
} // sendData()
void flushQueues(void) {
rcmd_queuereset();
#if (HAS_LORA)
lora_queuereset();
#endif
@@ -203,7 +202,7 @@ void flushQueues(void) {
}
bool allQueuesEmtpy(void) {
uint32_t rc = 0;
uint32_t rc = rcmd_queuewaiting();
#if (HAS_LORA)
rc += lora_queuewaiting();
#endif
+1 -1
View File
@@ -43,7 +43,7 @@ static const char TAG[] = __FILE__;
DMA_ATTR uint8_t txbuf[BUFFER_SIZE];
DMA_ATTR uint8_t rxbuf[BUFFER_SIZE];
QueueHandle_t SPISendQueue;
static QueueHandle_t SPISendQueue;
TaskHandle_t spiTask;
+3 -2
View File
@@ -109,8 +109,9 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec,
_seconds(), timeSetSymbols[mytimesource]);
} else {
timesyncer.attach(TIME_SYNC_INTERVAL_RETRY * 60, setTimeSyncIRQ);
ESP_LOGD(TAG, "[%0.3f] Timesync failed, invalid time fetched | source: %c",
_seconds(), timeSetSymbols[mytimesource]);
time_t unix_sec_at_compilation = compiledUTC();
ESP_LOGD(TAG, "[%0.3f] Failed to synchronise time from source %c | unix sec obtained from source: %d | unix sec at program compilation: %d",
_seconds(), timeSetSymbols[mytimesource], time_to_set, unix_sec_at_compilation);
}
}