From 5319f1c976b8b74b532de5d85763e4b99bb30e9a Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 7 May 2019 18:19:13 +0200 Subject: [PATCH 01/92] configure node-red for ttn app --- src/Timeserver/Nodered-Timeserver.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index 85e52607..b4d27d80 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -345,7 +345,7 @@ "type": "mqtt-broker", "z": "", "name": "eu.thethings.network:1883", - "broker": "eu.thethings.network", + "broker": "mqtt://paxcounter-timediff:ttn-account-v2.Fyf_ZgT4lBM2A3Gj-4SpNPp0-_tPkqtPRMJ_a-w1aT4@eu.thethings.network/", "port": "1883", "tls": "", "clientid": "", From 26c1cb0aaac487ee468d8d327840ab577cb1bf1f Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 7 May 2019 18:20:12 +0200 Subject: [PATCH 02/92] config for time sync via lora --- src/paxcounter.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 30dcedc0..9dffe04e 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -94,6 +94,7 @@ #define BMEPORT 7 // BME680 sensor #define BATTPORT 8 // battery voltage #define TIMEPORT 9 // time query +#define TIMEDIFFPORT 13 // time adjust diff #define TIMEANSWERPORT_MIN 0xA0 // time answer, start of port range #define TIMEANSWERPORT_MAX 0xDF // time answer, end of port range #define SENSOR1PORT 10 // user sensor #1 From fdc971be0484cd6af9d0ccc1665616b0397fa7fe Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 7 May 2019 18:20:59 +0200 Subject: [PATCH 03/92] send timediff with ms after time sync --- include/payload.h | 1 + src/payload.cpp | 15 +++++++++++---- src/timesync.cpp | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/include/payload.h b/include/payload.h index b41bb113..8ae86e6e 100644 --- a/include/payload.h +++ b/include/payload.h @@ -55,6 +55,7 @@ public: void addButton(uint8_t value); void addSensor(uint8_t[]); void addTime(time_t value); + void addTimeDiff(int32_t value); #if (PAYLOAD_ENCODER == 1) // format plain diff --git a/src/payload.cpp b/src/payload.cpp index 8afd0b3b..ac310c55 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -16,7 +16,14 @@ uint8_t *PayloadConvert::getBuffer(void) { return buffer; } /* ---------------- plain format without special encoding ---------- */ -#if (PAYLOAD_ENCODER == 1) +void PayloadConvert::addTimeDiff(int32_t value) { + buffer[cursor++] = (byte)((value & 0xFF000000) >> 24); + buffer[cursor++] = (byte)((value & 0x00FF0000) >> 16); + buffer[cursor++] = (byte)((value & 0x0000FF00) >> 8); + buffer[cursor++] = (byte)((value & 0x000000FF)); +} + +#if PAYLOAD_ENCODER == 1 void PayloadConvert::addByte(uint8_t value) { buffer[cursor++] = (value); } @@ -308,8 +315,8 @@ void PayloadConvert::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, #elif ((PAYLOAD_ENCODER == 3) || (PAYLOAD_ENCODER == 4)) -void PayloadConvert::addByte(uint8_t value) { - /* +void PayloadConvert::addByte(uint8_t value) { + /* not implemented */ } @@ -486,4 +493,4 @@ void PayloadConvert::addTime(time_t value) { #endif } -#endif \ No newline at end of file +#endif diff --git a/src/timesync.cpp b/src/timesync.cpp index ef50041d..2c5b5db0 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -240,7 +240,42 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, CLOCKIRQ(); // fire clock pps, this advances time 1 sec #endif - setTime(time_to_set); // set the time on top of second + struct timeval tv; + struct timezone tz; + if(gettimeofday(&tv, &tz) != 0) { + ESP_LOGI(TAG, "ERROR gettimeofday"); + } + struct timeval before = tv; + + struct timeval now; + now.tv_sec = t_sec; + now.tv_usec = t_msec; + if(settimeofday(&tv, &tz) != 0) { + ESP_LOGE(TAG, "ERROR settimeofday"); + } + + struct timeval diff; + diff.tv_sec = now.tv_sec-before.tv_sec; + diff.tv_usec = now.tv_usec-before.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); timeSource = mytimesource; // set global variable timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync); @@ -264,4 +299,4 @@ void timesync_init() { 1); // CPU core } -#endif \ No newline at end of file +#endif From 646d60e9c5e85ddadc5eb83eec2feebc95c3e10e Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 13 May 2019 14:30:56 +0200 Subject: [PATCH 04/92] t_sec corrected by one seconds because time is only set ontop of a second --- src/timesync.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/timesync.cpp b/src/timesync.cpp index 2c5b5db0..fa2030b2 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -208,8 +208,10 @@ int recv_timesync_ans(uint8_t seq_no, 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) { +void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec) { + + t_sec ++; + time_t time_to_set = (time_t)(t_sec); // increment t_sec only if t_msec > 1000 time_t time_to_set = (time_t)(t_sec + t_msec / 1000); From f475a634d558933c46eb32071bf274e59c7d31aa Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 13 May 2019 14:32:27 +0200 Subject: [PATCH 05/92] changed now to nowTime dow to conflict with function name now(), settimeofday got incorrect timevalue --- src/timesync.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/timesync.cpp b/src/timesync.cpp index fa2030b2..f50b0f5e 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -247,18 +247,18 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec) { if(gettimeofday(&tv, &tz) != 0) { ESP_LOGI(TAG, "ERROR gettimeofday"); } - struct timeval before = tv; + struct timeval beforeTime = tv; - struct timeval now; - now.tv_sec = t_sec; - now.tv_usec = t_msec; - if(settimeofday(&tv, &tz) != 0) { + 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 = now.tv_sec-before.tv_sec; - diff.tv_usec = now.tv_usec-before.tv_usec; + 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; From b00912277c797f2e1f289d3ea131f882796fbdfa Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Fri, 9 Aug 2019 14:02:10 +0200 Subject: [PATCH 06/92] send timestamp via uart for debugging --- src/uart.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/uart.h | 1 + 2 files changed, 46 insertions(+) create mode 100644 src/uart.cpp create mode 100644 src/uart.h diff --git a/src/uart.cpp b/src/uart.cpp new file mode 100644 index 00000000..52ac63f2 --- /dev/null +++ b/src/uart.cpp @@ -0,0 +1,45 @@ +#include +#include + +#include +#include "globals.h" +#include "driver/uart.h" + +void time_uart_send(void * pvParameters) { + struct timeval curTime; + + const char* format = "\bOAL%y%m%dF%H%M%S\r"; + char timestamp[64] = {0}; + TickType_t xLastWakeTime = xTaskGetTickCount(); + + for(;;) { + time_t nowTime = now(); + strftime(timestamp, sizeof(timestamp), format, localtime(&nowTime)); + ESP_LOGI(TAG, "Current Time: %s", timestamp); + + int len = strlen(timestamp)+1; + + // Send Data via UART + uart_write_bytes(UART_NUM_1, timestamp, len); + + // gettimeofday(&curTime, &tz); + int sleep = 1000 - (curTime.tv_usec/1000); + ostime_t now = os_getTime(); + printf("Sleep Time: %d, now: %d\n", sleep, now); + vTaskDelayUntil( &xLastWakeTime, (TickType_t)(sleep/portTICK_PERIOD_MS) ); + + // Read UART for testing purposes + /** + uint8_t *data = (uint8_t *) malloc(CLOCK_BUF_SIZE); + + // Read Data via UART + uart_read_bytes(UART_NUM_1, data, CLOCK_BUF_SIZE, 20 / portTICK_RATE_MS); + const char * dataC = (const char *) data; + ESP_LOGI(TAG, "Data Read: %s", dataC); + + free(data); + **/ + } + + vTaskDelete(NULL); +} diff --git a/src/uart.h b/src/uart.h new file mode 100644 index 00000000..78b81ed5 --- /dev/null +++ b/src/uart.h @@ -0,0 +1 @@ +void time_uart_send(void * pvParameters); From a1221ebad06d09e1e93b41bc5d211d7a41020f77 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 12 Aug 2019 16:11:39 +0200 Subject: [PATCH 07/92] lost in merging process --- src/timesync.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/timesync.cpp b/src/timesync.cpp index f50b0f5e..940696c5 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -208,13 +208,14 @@ int recv_timesync_ans(uint8_t seq_no, 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) { +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_t time_to_set = (time_t)(t_sec + t_msec / 1000); + time_to_set = (time_t)(t_sec + t_msec / 1000); // do we have a valid time? if (timeIsValid(time_to_set)) { From ce7d3ab2927e3678d9963386af53863c216e8d1e Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 13 Aug 2019 13:16:28 +0200 Subject: [PATCH 08/92] node-red server reconfigured (new broker & seqNo in payload) --- src/Timeserver/Nodered-Timeserver.json | 579 +++++++++++++------------ 1 file changed, 301 insertions(+), 278 deletions(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index b4d27d80..c823be78 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -1,198 +1,253 @@ [ { - "id": "49e3c067.e782e", - "type": "change", - "z": "449c1517.e25f4c", - "name": "Payload", - "rules": [ + "id":"656d6468.69133c", + "type":"tab", + "label":"Flow 1", + "disabled":false, + "info":"" + }, + { + "id":"2a15ab6f.ab2244", + "type":"mqtt-broker", + "z":"", + "name":"eu.thethings.network:1883", + "broker":"mqtt://xdot-gr:ttn-account-v2.eH0S7LsbltxCHjNTfMLcDc_mzhW2n4IN8GrtC-mKOXk@eu.thethings.network/", + "port":"1883", + "tls":"", + "clientid":"", + "usetls":false, + "compatmode":true, + "keepalive":"60", + "cleansession":true, + "birthTopic":"", + "birthQos":"0", + "birthPayload":"", + "closeTopic":"", + "closeQos":"0", + "closePayload":"", + "willTopic":"", + "willQos":"0", + "willPayload":"" + }, + { + "id":"edb7cc8d.a3817", + "type":"ui_group", + "z":"", + "name":"Timeserver", + "tab":"d525a5d.0832858", + "order":4, + "disp":true, + "width":"6", + "collapse":false + }, + { + "id":"d525a5d.0832858", + "type":"ui_tab", + "z":"", + "name":"Timeserver", + "icon":"sync", + "order":3, + "disabled":false, + "hidden":false + }, + { + "id":"49e3c067.e782e", + "type":"change", + "z":"656d6468.69133c", + "name":"Payload", + "rules":[ { - "t": "change", - "p": "topic", - "pt": "msg", - "from": "up", - "fromt": "str", - "to": "down", - "tot": "str" + "t":"change", + "p":"topic", + "pt":"msg", + "from":"up", + "fromt":"str", + "to":"down", + "tot":"str" }, { - "t": "set", - "p": "payload.confirmed", - "pt": "msg", - "to": "false", - "tot": "bool" + "t":"set", + "p":"payload.confirmed", + "pt":"msg", + "to":"false", + "tot":"bool" }, { - "t": "set", - "p": "payload.schedule", - "pt": "msg", - "to": "replace", - "tot": "str" + "t":"set", + "p":"payload.schedule", + "pt":"msg", + "to":"replace", + "tot":"str" }, { - "t": "move", - "p": "payload", - "pt": "msg", - "to": "payload.payload_raw", - "tot": "msg" + "t":"move", + "p":"payload", + "pt":"msg", + "to":"payload.payload_raw", + "tot":"msg" }, { - "t": "move", - "p": "port", - "pt": "msg", - "to": "payload.port", - "tot": "msg" + "t":"move", + "p":"port", + "pt":"msg", + "to":"payload.port", + "tot":"msg" } ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 240, - "y": 513, - "wires": [ + "action":"", + "property":"", + "from":"", + "to":"", + "reg":false, + "x":240, + "y":513, + "wires":[ [ "84f1cda2.069e7" ] ] }, { - "id": "cc140589.dea168", - "type": "mqtt in", - "z": "449c1517.e25f4c", - "name": "listen", - "topic": "+/devices/+/up", - "qos": "2", - "broker": "2a15ab6f.ab2244", - "x": 110, - "y": 120, - "wires": [ + "id":"cc140589.dea168", + "type":"mqtt in", + "z":"656d6468.69133c", + "name":"listen", + "topic":"+/devices/+/up", + "qos":"2", + "broker":"2a15ab6f.ab2244", + "x":110, + "y":120, + "wires":[ [ "4f97d75.6c87528" ] ] }, { - "id": "72d5e7ee.d1eba8", - "type": "mqtt out", - "z": "449c1517.e25f4c", - "name": "send", - "topic": "", - "qos": "", - "retain": "", - "broker": "2a15ab6f.ab2244", - "x": 730, - "y": 513, - "wires": [] + "id":"72d5e7ee.d1eba8", + "type":"mqtt out", + "z":"656d6468.69133c", + "name":"send", + "topic":"", + "qos":"", + "retain":"", + "broker":"2a15ab6f.ab2244", + "x":730, + "y":513, + "wires":[ + + ] }, { - "id": "4f97d75.6c87528", - "type": "json", - "z": "449c1517.e25f4c", - "name": "Convert", - "property": "payload", - "action": "", - "pretty": false, - "x": 260, - "y": 120, - "wires": [ + "id":"4f97d75.6c87528", + "type":"json", + "z":"656d6468.69133c", + "name":"Convert", + "property":"payload", + "action":"", + "pretty":false, + "x":260, + "y":120, + "wires":[ [ "9f4b8dd3.2f0d2" ] ] }, { - "id": "9f4b8dd3.2f0d2", - "type": "switch", - "z": "449c1517.e25f4c", - "name": "Timeport", - "property": "payload.port", - "propertyType": "msg", - "rules": [ + "id":"9f4b8dd3.2f0d2", + "type":"switch", + "z":"656d6468.69133c", + "name":"Timeport", + "property":"payload.port", + "propertyType":"msg", + "rules":[ { - "t": "eq", - "v": "9", - "vt": "num" + "t":"eq", + "v":"9", + "vt":"num" } ], - "checkall": "true", - "repair": false, - "outputs": 1, - "x": 420, - "y": 120, - "wires": [ + "checkall":"true", + "repair":false, + "outputs":1, + "x":420, + "y":120, + "wires":[ [ "8ed813a9.a9319" ] ] }, { - "id": "dac8aafa.389298", - "type": "json", - "z": "449c1517.e25f4c", - "name": "Convert", - "property": "payload", - "action": "", - "pretty": false, - "x": 580, - "y": 513, - "wires": [ + "id":"dac8aafa.389298", + "type":"json", + "z":"656d6468.69133c", + "name":"Convert", + "property":"payload", + "action":"", + "pretty":false, + "x":580, + "y":513, + "wires":[ [ "72d5e7ee.d1eba8" ] ] }, { - "id": "8ed813a9.a9319", - "type": "base64", - "z": "449c1517.e25f4c", - "name": "Decode", - "action": "", - "property": "payload.payload_raw", - "x": 580, - "y": 120, - "wires": [ + "id":"8ed813a9.a9319", + "type":"base64", + "z":"656d6468.69133c", + "name":"Decode", + "action":"", + "property":"payload.payload_raw", + "x":580, + "y":120, + "wires":[ [ "831ab883.d6a238" ] ] }, { - "id": "84f1cda2.069e7", - "type": "base64", - "z": "449c1517.e25f4c", - "name": "Encode", - "action": "", - "property": "payload.payload_raw", - "x": 420, - "y": 513, - "wires": [ + "id":"84f1cda2.069e7", + "type":"base64", + "z":"656d6468.69133c", + "name":"Encode", + "action":"", + "property":"payload.payload_raw", + "x":420, + "y":513, + "wires":[ [ "dac8aafa.389298" ] ] }, { - "id": "6190967b.01f758", - "type": "comment", - "z": "449c1517.e25f4c", - "name": "LoRaWAN Timeserver v1.1", - "info": "PLEASE NOTE: There is a patent filed for the time sync algorithm used in the\ncode of this file. The shown implementation example is covered by the\nrepository's licencse, but you may not be eligible to deploy the applied\nalgorithm in applications without granted license by the patent holder.", - "x": 170, - "y": 40, - "wires": [] + "id":"6190967b.01f758", + "type":"comment", + "z":"656d6468.69133c", + "name":"LoRaWAN Timeserver v1.1", + "info":"PLEASE NOTE: There is a patent filed for the time sync algorithm used in the\ncode of this file. The shown implementation example is covered by the\nrepository's licencse, but you may not be eligible to deploy the applied\nalgorithm in applications without granted license by the patent holder.", + "x":170, + "y":40, + "wires":[ + + ] }, { - "id": "831ab883.d6a238", - "type": "function", - "z": "449c1517.e25f4c", - "name": "Timeserver Logic", - "func": "/* LoRaWAN Timeserver\n\nconstruct 5 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\nFPort = sequence number (taken from node's time_sync_req)\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload.payload_raw[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(5);\nnew DataView(buf).setUint32(0, seconds);\nnew DataView(buf).setUint8(4, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = seqNo;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", - "outputs": 5, - "noerr": 0, - "x": 350, - "y": 320, - "wires": [ + "id":"831ab883.d6a238", + "type":"function", + "z":"656d6468.69133c", + "name":"Timeserver Logic", + "func":"/* LoRaWAN Timeserver\n\nconstruct 5 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\nFPort = sequence number (taken from node's time_sync_req)\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload.payload_raw[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(6);\nnew DataView(buf).setUint8(0, seqNo);\nnew DataView(buf).setUint32(1, seconds);\nnew DataView(buf).setUint8(5, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", + "outputs":5, + "noerr":0, + "x":350, + "y":320, + "wires":[ [ "37722d4b.08e3c2", "a8a04c7a.c5fbd", @@ -211,7 +266,7 @@ "49e3c067.e782e" ] ], - "outputLabels": [ + "outputLabels":[ "gw_eui", "offset_ms", "device", @@ -220,168 +275,136 @@ ] }, { - "id": "37722d4b.08e3c2", - "type": "debug", - "z": "449c1517.e25f4c", - "name": "Timeserver Gw", - "active": true, - "tosidebar": false, - "console": false, - "tostatus": true, - "complete": "payload", - "x": 700, - "y": 240, - "wires": [], - "icon": "node-red/bridge.png" + "id":"37722d4b.08e3c2", + "type":"debug", + "z":"656d6468.69133c", + "name":"Timeserver Gw", + "active":true, + "tosidebar":false, + "console":false, + "tostatus":true, + "complete":"payload", + "x":700, + "y":240, + "wires":[ + + ], + "icon":"node-red/bridge.png" }, { - "id": "8712a5ac.ed18e8", - "type": "ui_text", - "z": "449c1517.e25f4c", - "group": "edb7cc8d.a3817", - "order": 3, - "width": 0, - "height": 0, - "name": "Recent time", - "label": "Last answer at:", - "format": "{{msg.payload}}", - "layout": "col-center", - "x": 810, - "y": 300, - "wires": [] + "id":"8712a5ac.ed18e8", + "type":"ui_text", + "z":"656d6468.69133c", + "group":"edb7cc8d.a3817", + "order":3, + "width":0, + "height":0, + "name":"Recent time", + "label":"Last answer at:", + "format":"{{msg.payload}}", + "layout":"col-center", + "x":810, + "y":300, + "wires":[ + + ] }, { - "id": "46ce842a.614d5c", - "type": "ui_gauge", - "z": "449c1517.e25f4c", - "name": "Timeserver offset", - "group": "edb7cc8d.a3817", - "order": 2, - "width": 0, - "height": 0, - "gtype": "gage", - "title": "Offset gateway to server", - "label": "milliseconds", - "format": "{{value}}", - "min": 0, - "max": "2000", - "colors": [ + "id":"46ce842a.614d5c", + "type":"ui_gauge", + "z":"656d6468.69133c", + "name":"Timeserver offset", + "group":"edb7cc8d.a3817", + "order":2, + "width":0, + "height":0, + "gtype":"gage", + "title":"Offset gateway to server", + "label":"milliseconds", + "format":"{{value}}", + "min":0, + "max":"2000", + "colors":[ "#00b500", "#e6e600", "#ca3838" ], - "seg1": "", - "seg2": "", - "x": 710, - "y": 380, - "wires": [] + "seg1":"", + "seg2":"", + "x":710, + "y":380, + "wires":[ + + ] }, { - "id": "a8a04c7a.c5fbd", - "type": "ui_text", - "z": "449c1517.e25f4c", - "group": "edb7cc8d.a3817", - "order": 1, - "width": 0, - "height": 0, - "name": "Recent server", - "label": "Gateway", - "format": "{{msg.payload}}", - "layout": "col-center", - "x": 700, - "y": 340, - "wires": [] + "id":"a8a04c7a.c5fbd", + "type":"ui_text", + "z":"656d6468.69133c", + "group":"edb7cc8d.a3817", + "order":1, + "width":0, + "height":0, + "name":"Recent server", + "label":"Gateway", + "format":"{{msg.payload}}", + "layout":"col-center", + "x":700, + "y":340, + "wires":[ + + ] }, { - "id": "a15454a9.fa0948", - "type": "function", - "z": "449c1517.e25f4c", - "name": "Time", - "func": "msg.payload = new Date().toLocaleString('en-GB', {timeZone: 'Europe/Berlin'});\nreturn msg;", - "outputs": 1, - "noerr": 0, - "x": 670, - "y": 300, - "wires": [ + "id":"a15454a9.fa0948", + "type":"function", + "z":"656d6468.69133c", + "name":"Time", + "func":"msg.payload = new Date().toLocaleString('en-GB', {timeZone: 'Europe/Berlin'});\nreturn msg;", + "outputs":1, + "noerr":0, + "x":670, + "y":300, + "wires":[ [ "8712a5ac.ed18e8" ] ] }, { - "id": "a5dbb4ef.019168", - "type": "ui_text", - "z": "449c1517.e25f4c", - "group": "edb7cc8d.a3817", - "order": 1, - "width": 0, - "height": 0, - "name": "Recent Device", - "label": "Device", - "format": "{{msg.payload}}", - "layout": "col-center", - "x": 700, - "y": 420, - "wires": [] + "id":"a5dbb4ef.019168", + "type":"ui_text", + "z":"656d6468.69133c", + "group":"edb7cc8d.a3817", + "order":1, + "width":0, + "height":0, + "name":"Recent Device", + "label":"Device", + "format":"{{msg.payload}}", + "layout":"col-center", + "x":700, + "y":420, + "wires":[ + + ] }, { - "id": "1cb58e7f.221362", - "type": "ui_text", - "z": "449c1517.e25f4c", - "group": "edb7cc8d.a3817", - "order": 1, - "width": 0, - "height": 0, - "name": "Sequence No", - "label": "Sequence", - "format": "{{msg.payload}}", - "layout": "col-center", - "x": 700, - "y": 460, - "wires": [] - }, - { - "id": "2a15ab6f.ab2244", - "type": "mqtt-broker", - "z": "", - "name": "eu.thethings.network:1883", - "broker": "mqtt://paxcounter-timediff:ttn-account-v2.Fyf_ZgT4lBM2A3Gj-4SpNPp0-_tPkqtPRMJ_a-w1aT4@eu.thethings.network/", - "port": "1883", - "tls": "", - "clientid": "", - "usetls": false, - "compatmode": true, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "edb7cc8d.a3817", - "type": "ui_group", - "z": "", - "name": "Timeserver", - "tab": "d525a5d.0832858", - "order": 4, - "disp": true, - "width": "6", - "collapse": false - }, - { - "id": "d525a5d.0832858", - "type": "ui_tab", - "z": "", - "name": "Timeserver", - "icon": "sync", - "order": 3, - "disabled": false, - "hidden": false + "id":"1cb58e7f.221362", + "type":"ui_text", + "z":"656d6468.69133c", + "group":"edb7cc8d.a3817", + "order":1, + "width":0, + "height":0, + "name":"Sequence No", + "label":"Sequence", + "format":"{{msg.payload}}", + "layout":"col-center", + "x":700, + "y":460, + "wires":[ + + ] } -] \ No newline at end of file +] From 730f35babff6a96d26b01b866bc57dc3744d757b Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 13 Aug 2019 13:16:56 +0200 Subject: [PATCH 09/92] expect seqNo in payload and not in port --- include/timesync.h | 2 +- src/lorawan.cpp | 6 +++--- src/timesync.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/timesync.h b/include/timesync.h index 498952c1..286d82e7 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -7,7 +7,7 @@ #include "timekeeper.h" //#define TIME_SYNC_TRIGGER 100 // threshold for time sync [milliseconds] -#define TIME_SYNC_FRAME_LENGTH 0x05 // timeserver answer frame length [bytes] +#define TIME_SYNC_FRAME_LENGTH 0x06 // timeserver answer frame length [bytes] #define TIME_SYNC_FIXUP 4 // calibration to fixup processing time [milliseconds] void timesync_init(void); diff --git a/src/lorawan.cpp b/src/lorawan.cpp index e82ac1f5..b5e941cb 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -265,9 +265,9 @@ void onEvent(ev_t ev) { #if (TIME_SYNC_LORASERVER) // timesync answer -> call timesync processor - if ((LMIC.frame[LMIC.dataBeg - 1] >= TIMEANSWERPORT_MIN) && - (LMIC.frame[LMIC.dataBeg - 1] <= TIMEANSWERPORT_MAX)) { - recv_timesync_ans(LMIC.frame[LMIC.dataBeg - 1], + if ((LMIC.frame[LMIC.dataBeg] >= TIMEANSWERPORT_MIN) && + (LMIC.frame[LMIC.dataBeg] <= TIMEANSWERPORT_MAX)) { + recv_timesync_ans(LMIC.frame[LMIC.dataBeg], LMIC.frame + LMIC.dataBeg, LMIC.dataLen); break; } diff --git a/src/timesync.cpp b/src/timesync.cpp index 940696c5..488561c2 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -174,15 +174,15 @@ int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len) { else { // we received a probably valid time frame uint8_t k = seq_no % TIME_SYNC_SAMPLES; - + uint8_t *timestamp_buf = buf+1; // 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]; + uint16_t timestamp_msec = 4 * timestamp_buf[4]; // pointers to 4 bytes 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 - timestamp_ptr = (uint32_t *)buf; + timestamp_ptr = (uint32_t *)timestamp_buf; // swap byte order from msb to lsb, note: this is platform dependent timestamp_sec = __builtin_bswap32(*timestamp_ptr); From 6894d718e63c919f11be1b6545521aa71597e610 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 27 Aug 2019 15:40:33 +0200 Subject: [PATCH 10/92] node-red config with use of ttn nodes --- src/Timeserver/Nodered-Timeserver.json | 854 +++++++++++++------------ 1 file changed, 459 insertions(+), 395 deletions(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index c823be78..3d057c76 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -1,410 +1,474 @@ [ - { - "id":"656d6468.69133c", - "type":"tab", - "label":"Flow 1", - "disabled":false, - "info":"" - }, - { - "id":"2a15ab6f.ab2244", - "type":"mqtt-broker", - "z":"", - "name":"eu.thethings.network:1883", - "broker":"mqtt://xdot-gr:ttn-account-v2.eH0S7LsbltxCHjNTfMLcDc_mzhW2n4IN8GrtC-mKOXk@eu.thethings.network/", - "port":"1883", - "tls":"", - "clientid":"", - "usetls":false, - "compatmode":true, - "keepalive":"60", - "cleansession":true, - "birthTopic":"", - "birthQos":"0", - "birthPayload":"", - "closeTopic":"", - "closeQos":"0", - "closePayload":"", - "willTopic":"", - "willQos":"0", - "willPayload":"" - }, - { - "id":"edb7cc8d.a3817", - "type":"ui_group", - "z":"", - "name":"Timeserver", - "tab":"d525a5d.0832858", - "order":4, - "disp":true, - "width":"6", - "collapse":false - }, - { - "id":"d525a5d.0832858", - "type":"ui_tab", - "z":"", - "name":"Timeserver", - "icon":"sync", - "order":3, - "disabled":false, - "hidden":false - }, - { - "id":"49e3c067.e782e", - "type":"change", - "z":"656d6468.69133c", - "name":"Payload", - "rules":[ - { - "t":"change", - "p":"topic", - "pt":"msg", - "from":"up", - "fromt":"str", - "to":"down", - "tot":"str" + { + "id":"23a9162c.cb1e6a", + "type":"tab", + "label":"Flow 1", + "disabled":false, + "info":"" + }, + { + "id":"2a15ab6f.ab2244", + "type":"mqtt-broker", + "z":"", + "name":"mqtt://db-clock-update-test:ttn-account-v2.etVLJSGCzS5ExuDw59HtGUIzv9Kcu8UPT_eWiz8ARs0@eu.thethings.network", + "broker":"mqtt://db-clock-update-test:ttn-account-v2.etVLJSGCzS5ExuDw59HtGUIzv9Kcu8UPT_eWiz8ARs0@eu.thethings.network", + "port":"1883", + "tls":"", + "clientid":"", + "usetls":false, + "compatmode":true, + "keepalive":"60", + "cleansession":true, + "birthTopic":"", + "birthQos":"0", + "birthPayload":"", + "closeTopic":"", + "closeQos":"0", + "closePayload":"", + "willTopic":"", + "willQos":"0", + "willPayload":"" + }, + { + "id":"edb7cc8d.a3817", + "type":"ui_group", + "z":"", + "name":"Timeserver", + "tab":"d525a5d.0832858", + "order":4, + "disp":true, + "width":"6", + "collapse":false + }, + { + "id":"d525a5d.0832858", + "type":"ui_tab", + "z":"", + "name":"Timeserver", + "icon":"sync", + "order":3, + "disabled":false, + "hidden":false + }, + { + "id":"428b4734.d61248", + "type":"ui_base", + "theme":{ + "name":"theme-light", + "lightTheme":{ + "default":"#0094CE", + "baseColor":"#0094CE", + "baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited":true, + "reset":false + }, + "darkTheme":{ + "default":"#097479", + "baseColor":"#097479", + "baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited":false + }, + "customTheme":{ + "name":"Untitled Theme 1", + "default":"#4B7930", + "baseColor":"#4B7930", + "baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + }, + "themeState":{ + "base-color":{ + "default":"#0094CE", + "value":"#0094CE", + "edited":false }, - { - "t":"set", - "p":"payload.confirmed", - "pt":"msg", - "to":"false", - "tot":"bool" + "page-titlebar-backgroundColor":{ + "value":"#0094CE", + "edited":false }, - { - "t":"set", - "p":"payload.schedule", - "pt":"msg", - "to":"replace", - "tot":"str" + "page-backgroundColor":{ + "value":"#fafafa", + "edited":false }, - { - "t":"move", - "p":"payload", - "pt":"msg", - "to":"payload.payload_raw", - "tot":"msg" + "page-sidebar-backgroundColor":{ + "value":"#ffffff", + "edited":false }, - { - "t":"move", - "p":"port", - "pt":"msg", - "to":"payload.port", - "tot":"msg" + "group-textColor":{ + "value":"#1bbfff", + "edited":false + }, + "group-borderColor":{ + "value":"#ffffff", + "edited":false + }, + "group-backgroundColor":{ + "value":"#ffffff", + "edited":false + }, + "widget-textColor":{ + "value":"#111111", + "edited":false + }, + "widget-backgroundColor":{ + "value":"#0094ce", + "edited":false + }, + "widget-borderColor":{ + "value":"#ffffff", + "edited":false + }, + "base-font":{ + "value":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" } - ], - "action":"", - "property":"", - "from":"", - "to":"", - "reg":false, - "x":240, - "y":513, - "wires":[ - [ - "84f1cda2.069e7" - ] - ] - }, - { - "id":"cc140589.dea168", - "type":"mqtt in", - "z":"656d6468.69133c", - "name":"listen", - "topic":"+/devices/+/up", - "qos":"2", - "broker":"2a15ab6f.ab2244", - "x":110, - "y":120, - "wires":[ - [ - "4f97d75.6c87528" - ] - ] - }, - { - "id":"72d5e7ee.d1eba8", - "type":"mqtt out", - "z":"656d6468.69133c", - "name":"send", - "topic":"", - "qos":"", - "retain":"", - "broker":"2a15ab6f.ab2244", - "x":730, - "y":513, - "wires":[ + }, + "angularTheme":{ + "primary":"indigo", + "accents":"blue", + "warn":"red", + "background":"grey" + } + }, + "site":{ + "name":"Node-RED Dashboard", + "hideToolbar":"false", + "allowSwipe":"false", + "lockMenu":"false", + "allowTempTheme":"true", + "dateFormat":"DD/MM/YYYY", + "sizes":{ + "sx":48, + "sy":48, + "gx":6, + "gy":6, + "cx":6, + "cy":6, + "px":0, + "py":0 + } + } + }, + { + "id":"f8f8391b.7e8728", + "type":"ttn app", + "z":"", + "appId":"db-clock-update-test", + "accessKey":"ttn-account-v2.etVLJSGCzS5ExuDw59HtGUIzv9Kcu8UPT_eWiz8ARs0", + "discovery":"discovery.thethingsnetwork.org:1900" + }, + { + "id":"49e3c067.e782e", + "type":"change", + "z":"23a9162c.cb1e6a", + "name":"Payload", + "rules":[ + { + "t":"change", + "p":"topic", + "pt":"msg", + "from":"up", + "fromt":"str", + "to":"down", + "tot":"str" + }, + { + "t":"set", + "p":"confirmed", + "pt":"msg", + "to":"false", + "tot":"bool" + }, + { + "t":"set", + "p":"schedule", + "pt":"msg", + "to":"replace", + "tot":"str" + } + ], + "action":"", + "property":"", + "from":"", + "to":"", + "reg":false, + "x":360, + "y":600, + "wires":[ + [ + "813b9751.dba8a8", + "5aff6f87.f125a" + ] + ] + }, + { + "id":"9f4b8dd3.2f0d2", + "type":"switch", + "z":"23a9162c.cb1e6a", + "name":"Timeport", + "property":"port", + "propertyType":"msg", + "rules":[ + { + "t":"eq", + "v":"9", + "vt":"num" + } + ], + "checkall":"true", + "repair":false, + "outputs":1, + "x":420, + "y":120, + "wires":[ + [ + "831ab883.d6a238", + "b1e45e31.61136" + ] + ] + }, + { + "id":"6190967b.01f758", + "type":"comment", + "z":"23a9162c.cb1e6a", + "name":"LoRaWAN Timeserver v1.1", + "info":"PLEASE NOTE: There is a patent filed for the time sync algorithm used in the\ncode of this file. The shown implementation example is covered by the\nrepository's licencse, but you may not be eligible to deploy the applied\nalgorithm in applications without granted license by the patent holder.", + "x":170, + "y":40, + "wires":[ - ] - }, - { - "id":"4f97d75.6c87528", - "type":"json", - "z":"656d6468.69133c", - "name":"Convert", - "property":"payload", - "action":"", - "pretty":false, - "x":260, - "y":120, - "wires":[ - [ - "9f4b8dd3.2f0d2" - ] - ] - }, - { - "id":"9f4b8dd3.2f0d2", - "type":"switch", - "z":"656d6468.69133c", - "name":"Timeport", - "property":"payload.port", - "propertyType":"msg", - "rules":[ - { - "t":"eq", - "v":"9", - "vt":"num" - } - ], - "checkall":"true", - "repair":false, - "outputs":1, - "x":420, - "y":120, - "wires":[ - [ - "8ed813a9.a9319" - ] - ] - }, - { - "id":"dac8aafa.389298", - "type":"json", - "z":"656d6468.69133c", - "name":"Convert", - "property":"payload", - "action":"", - "pretty":false, - "x":580, - "y":513, - "wires":[ - [ - "72d5e7ee.d1eba8" - ] - ] - }, - { - "id":"8ed813a9.a9319", - "type":"base64", - "z":"656d6468.69133c", - "name":"Decode", - "action":"", - "property":"payload.payload_raw", - "x":580, - "y":120, - "wires":[ - [ - "831ab883.d6a238" - ] - ] - }, - { - "id":"84f1cda2.069e7", - "type":"base64", - "z":"656d6468.69133c", - "name":"Encode", - "action":"", - "property":"payload.payload_raw", - "x":420, - "y":513, - "wires":[ - [ - "dac8aafa.389298" - ] - ] - }, - { - "id":"6190967b.01f758", - "type":"comment", - "z":"656d6468.69133c", - "name":"LoRaWAN Timeserver v1.1", - "info":"PLEASE NOTE: There is a patent filed for the time sync algorithm used in the\ncode of this file. The shown implementation example is covered by the\nrepository's licencse, but you may not be eligible to deploy the applied\nalgorithm in applications without granted license by the patent holder.", - "x":170, - "y":40, - "wires":[ + ] + }, + { + "id":"831ab883.d6a238", + "type":"function", + "z":"23a9162c.cb1e6a", + "name":"Timeserver Logic", + "func":"/* LoRaWAN Timeserver\n\nconstruct 5 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\nFPort = sequence number (taken from node's time_sync_req)\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload[\"timesync_seqno\"];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(6);\nnew DataView(buf).setUint8(0, seqNo);\nnew DataView(buf).setUint32(1, seconds);\nnew DataView(buf).setUint8(5, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", + "outputs":5, + "noerr":0, + "x":350, + "y":320, + "wires":[ + [ + "37722d4b.08e3c2", + "a8a04c7a.c5fbd", + "a15454a9.fa0948" + ], + [ + "46ce842a.614d5c" + ], + [ + "a5dbb4ef.019168" + ], + [ + "1cb58e7f.221362" + ], + [ + "49e3c067.e782e" + ] + ], + "outputLabels":[ + "gw_eui", + "offset_ms", + "device", + "seq_no", + "time_sync_ans" + ] + }, + { + "id":"37722d4b.08e3c2", + "type":"debug", + "z":"23a9162c.cb1e6a", + "name":"Timeserver Gw", + "active":true, + "tosidebar":false, + "console":false, + "tostatus":true, + "complete":"payload", + "x":700, + "y":240, + "wires":[ - ] - }, - { - "id":"831ab883.d6a238", - "type":"function", - "z":"656d6468.69133c", - "name":"Timeserver Logic", - "func":"/* LoRaWAN Timeserver\n\nconstruct 5 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\nFPort = sequence number (taken from node's time_sync_req)\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload.payload_raw[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(6);\nnew DataView(buf).setUint8(0, seqNo);\nnew DataView(buf).setUint32(1, seconds);\nnew DataView(buf).setUint8(5, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", - "outputs":5, - "noerr":0, - "x":350, - "y":320, - "wires":[ - [ - "37722d4b.08e3c2", - "a8a04c7a.c5fbd", - "a15454a9.fa0948" - ], - [ - "46ce842a.614d5c" - ], - [ - "a5dbb4ef.019168" - ], - [ - "1cb58e7f.221362" - ], - [ - "49e3c067.e782e" - ] - ], - "outputLabels":[ - "gw_eui", - "offset_ms", - "device", - "seq_no", - "time_sync_ans" - ] - }, - { - "id":"37722d4b.08e3c2", - "type":"debug", - "z":"656d6468.69133c", - "name":"Timeserver Gw", - "active":true, - "tosidebar":false, - "console":false, - "tostatus":true, - "complete":"payload", - "x":700, - "y":240, - "wires":[ + ], + "icon":"node-red/bridge.png" + }, + { + "id":"8712a5ac.ed18e8", + "type":"ui_text", + "z":"23a9162c.cb1e6a", + "group":"edb7cc8d.a3817", + "order":3, + "width":0, + "height":0, + "name":"Recent time", + "label":"Last answer at:", + "format":"{{msg.payload}}", + "layout":"col-center", + "x":810, + "y":300, + "wires":[ - ], - "icon":"node-red/bridge.png" - }, - { - "id":"8712a5ac.ed18e8", - "type":"ui_text", - "z":"656d6468.69133c", - "group":"edb7cc8d.a3817", - "order":3, - "width":0, - "height":0, - "name":"Recent time", - "label":"Last answer at:", - "format":"{{msg.payload}}", - "layout":"col-center", - "x":810, - "y":300, - "wires":[ + ] + }, + { + "id":"46ce842a.614d5c", + "type":"ui_gauge", + "z":"23a9162c.cb1e6a", + "name":"Timeserver offset", + "group":"edb7cc8d.a3817", + "order":2, + "width":0, + "height":0, + "gtype":"gage", + "title":"Offset gateway to server", + "label":"milliseconds", + "format":"{{value}}", + "min":0, + "max":"2000", + "colors":[ + "#00b500", + "#e6e600", + "#ca3838" + ], + "seg1":"", + "seg2":"", + "x":710, + "y":380, + "wires":[ - ] - }, - { - "id":"46ce842a.614d5c", - "type":"ui_gauge", - "z":"656d6468.69133c", - "name":"Timeserver offset", - "group":"edb7cc8d.a3817", - "order":2, - "width":0, - "height":0, - "gtype":"gage", - "title":"Offset gateway to server", - "label":"milliseconds", - "format":"{{value}}", - "min":0, - "max":"2000", - "colors":[ - "#00b500", - "#e6e600", - "#ca3838" - ], - "seg1":"", - "seg2":"", - "x":710, - "y":380, - "wires":[ + ] + }, + { + "id":"a8a04c7a.c5fbd", + "type":"ui_text", + "z":"23a9162c.cb1e6a", + "group":"edb7cc8d.a3817", + "order":1, + "width":0, + "height":0, + "name":"Recent server", + "label":"Gateway", + "format":"{{msg.payload}}", + "layout":"col-center", + "x":700, + "y":340, + "wires":[ - ] - }, - { - "id":"a8a04c7a.c5fbd", - "type":"ui_text", - "z":"656d6468.69133c", - "group":"edb7cc8d.a3817", - "order":1, - "width":0, - "height":0, - "name":"Recent server", - "label":"Gateway", - "format":"{{msg.payload}}", - "layout":"col-center", - "x":700, - "y":340, - "wires":[ + ] + }, + { + "id":"a15454a9.fa0948", + "type":"function", + "z":"23a9162c.cb1e6a", + "name":"Time", + "func":"msg.payload = new Date().toLocaleString('en-GB', {timeZone: 'Europe/Berlin'});\nreturn msg;", + "outputs":1, + "noerr":0, + "x":670, + "y":300, + "wires":[ + [ + "8712a5ac.ed18e8" + ] + ] + }, + { + "id":"a5dbb4ef.019168", + "type":"ui_text", + "z":"23a9162c.cb1e6a", + "group":"edb7cc8d.a3817", + "order":1, + "width":0, + "height":0, + "name":"Recent Device", + "label":"Device", + "format":"{msg.payload}", + "layout":"col-center", + "x":700, + "y":420, + "wires":[ - ] - }, - { - "id":"a15454a9.fa0948", - "type":"function", - "z":"656d6468.69133c", - "name":"Time", - "func":"msg.payload = new Date().toLocaleString('en-GB', {timeZone: 'Europe/Berlin'});\nreturn msg;", - "outputs":1, - "noerr":0, - "x":670, - "y":300, - "wires":[ - [ - "8712a5ac.ed18e8" - ] - ] - }, - { - "id":"a5dbb4ef.019168", - "type":"ui_text", - "z":"656d6468.69133c", - "group":"edb7cc8d.a3817", - "order":1, - "width":0, - "height":0, - "name":"Recent Device", - "label":"Device", - "format":"{{msg.payload}}", - "layout":"col-center", - "x":700, - "y":420, - "wires":[ + ] + }, + { + "id":"1cb58e7f.221362", + "type":"ui_text", + "z":"23a9162c.cb1e6a", + "group":"edb7cc8d.a3817", + "order":1, + "width":0, + "height":0, + "name":"Sequence No", + "label":"Sequence", + "format":"{{msg.payload}}", + "layout":"col-center", + "x":700, + "y":460, + "wires":[ - ] - }, - { - "id":"1cb58e7f.221362", - "type":"ui_text", - "z":"656d6468.69133c", - "group":"edb7cc8d.a3817", - "order":1, - "width":0, - "height":0, - "name":"Sequence No", - "label":"Sequence", - "format":"{{msg.payload}}", - "layout":"col-center", - "x":700, - "y":460, - "wires":[ + ] + }, + { + "id":"a5356ffb.f0cab", + "type":"ttn uplink", + "z":"23a9162c.cb1e6a", + "name":"", + "app":"f8f8391b.7e8728", + "dev_id":"", + "field":"", + "x":240, + "y":120, + "wires":[ + [ + "9f4b8dd3.2f0d2" + ] + ] + }, + { + "id":"813b9751.dba8a8", + "type":"debug", + "z":"23a9162c.cb1e6a", + "name":"", + "active":true, + "tosidebar":true, + "console":false, + "tostatus":false, + "complete":"false", + "x":590, + "y":640, + "wires":[ - ] - } + ] + }, + { + "id":"5aff6f87.f125a", + "type":"ttn downlink", + "z":"23a9162c.cb1e6a", + "name":"", + "app":"f8f8391b.7e8728", + "dev_id":"", + "port":"", + "confirmed":false, + "schedule":"replace", + "x":590, + "y":560, + "wires":[ + + ] + }, + { + "id":"b1e45e31.61136", + "type":"debug", + "z":"23a9162c.cb1e6a", + "name":"", + "active":true, + "tosidebar":true, + "console":false, + "tostatus":false, + "complete":"payload", + "targetType":"msg", + "x":590, + "y":100, + "wires":[ + + ] + } ] From cab44588c79d1d09ed0de076690942829b3ff88d Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 27 Aug 2019 16:00:25 +0200 Subject: [PATCH 11/92] start uart timestamp send when time has been synced --- src/timesync.cpp | 2 ++ src/uart.cpp | 18 +++++++++++++++++- src/uart.h | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/timesync.cpp b/src/timesync.cpp index 488561c2..09e28b3b 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -12,6 +12,7 @@ algorithm in applications without granted license by the patent holder. #if (TIME_SYNC_LORASERVER) && (HAS_LORA) #include "timesync.h" +#include "uart.h" // Local logging tag static const char TAG[] = __FILE__; @@ -282,6 +283,7 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, 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 { diff --git a/src/uart.cpp b/src/uart.cpp index 52ac63f2..1303cbf5 100644 --- a/src/uart.cpp +++ b/src/uart.cpp @@ -5,6 +5,9 @@ #include "globals.h" #include "driver/uart.h" +static const char TAG[] = __FILE__; +TaskHandle_t UartTask = NULL; + void time_uart_send(void * pvParameters) { struct timeval curTime; @@ -25,7 +28,7 @@ void time_uart_send(void * pvParameters) { // gettimeofday(&curTime, &tz); int sleep = 1000 - (curTime.tv_usec/1000); ostime_t now = os_getTime(); - printf("Sleep Time: %d, now: %d\n", sleep, now); + ESP_LOGD(TAG, "Sleep Time: %d, now: %d\n", sleep, now); vTaskDelayUntil( &xLastWakeTime, (TickType_t)(sleep/portTICK_PERIOD_MS) ); // Read UART for testing purposes @@ -43,3 +46,16 @@ void time_uart_send(void * pvParameters) { vTaskDelete(NULL); } + +void time_uart_send_start() { + if (UartTask) { + return; + } + xTaskCreatePinnedToCore(time_uart_send, // task function + "time_uart_send", // name of task + 2048, // stack size of task + (void *)1, // parameter of the task + 2, // priority of the task + &UartTask, // task handle + 1); // CPU core +} diff --git a/src/uart.h b/src/uart.h index 78b81ed5..612aabbe 100644 --- a/src/uart.h +++ b/src/uart.h @@ -1 +1,2 @@ void time_uart_send(void * pvParameters); +void time_uart_send_start(); From 4a573bc638a747b4838d0ab486786f680c33558a Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 27 Aug 2019 17:27:57 +0200 Subject: [PATCH 12/92] send time via uart --- include/main.h | 1 + src/main.cpp | 2 ++ src/uart.cpp | 24 +++++++++++++++++++++++- src/uart.h | 13 +++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/main.h b/include/main.h index bce12e51..215aa47e 100644 --- a/include/main.h +++ b/include/main.h @@ -16,6 +16,7 @@ #include "irqhandler.h" #include "led.h" #include "spislave.h" +#include "uart.h" #if(HAS_LORA) #include "lorawan.h" #endif diff --git a/src/main.cpp b/src/main.cpp index c6dae99e..2a7aab1a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -444,6 +444,8 @@ void setup() { // show compiled features ESP_LOGI(TAG, "Features:%s", features); + uart_setup(); + } // setup() void loop() { diff --git a/src/uart.cpp b/src/uart.cpp index 1303cbf5..b71b3e28 100644 --- a/src/uart.cpp +++ b/src/uart.cpp @@ -1,13 +1,30 @@ +#include "rtctime.h" + #include #include #include #include "globals.h" +#include "uart.h" #include "driver/uart.h" static const char TAG[] = __FILE__; TaskHandle_t UartTask = NULL; +void uart_setup() { + // setup UART connection + uart_config_t uart_config = { + .baud_rate = 9600, + .data_bits = UART_DATA_7_BITS, + .parity = UART_PARITY_EVEN, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + }; + uart_param_config(UART_NUM_1, &uart_config); + uart_set_pin(UART_NUM_1, CLOCK_DCF_TXD, CLOCK_DCF_RXD, CLOCK_DCF_RTS, CLOCK_DCF_CTS); + uart_driver_install(UART_NUM_1, CLOCK_BUF_SIZE * 2, 0, 0, NULL, 0); +} + void time_uart_send(void * pvParameters) { struct timeval curTime; @@ -16,7 +33,12 @@ void time_uart_send(void * pvParameters) { TickType_t xLastWakeTime = xTaskGetTickCount(); for(;;) { - time_t nowTime = now(); + struct timeval tv; + struct timezone tz; + if(gettimeofday(&tv, &tz) != 0) { + ESP_LOGI(TAG, "ERROR gettimeofday"); + } + time_t nowTime = tv.tv_sec; strftime(timestamp, sizeof(timestamp), format, localtime(&nowTime)); ESP_LOGI(TAG, "Current Time: %s", timestamp); diff --git a/src/uart.h b/src/uart.h index 612aabbe..f12acbaf 100644 --- a/src/uart.h +++ b/src/uart.h @@ -1,2 +1,15 @@ +#ifndef UART_H +#define UART_H + +// UART for Clock DCF +#define CLOCK_DCF_TXD (GPIO_NUM_4) +#define CLOCK_DCF_RXD (GPIO_NUM_15) +#define CLOCK_DCF_RTS (UART_PIN_NO_CHANGE) +#define CLOCK_DCF_CTS (UART_PIN_NO_CHANGE) +#define CLOCK_BUF_SIZE (1024) + void time_uart_send(void * pvParameters); void time_uart_send_start(); +void uart_setup(); + +#endif From 4d42c961b22b697eac107e627a315a69a8df93ca Mon Sep 17 00:00:00 2001 From: Florian Ludwig Date: Thu, 29 Aug 2019 10:32:55 +0300 Subject: [PATCH 13/92] move timesync seq_no into message body from port --- include/timesync.h | 2 +- src/lorawan.cpp | 6 ++---- src/paxcounter.conf | 7 +++---- src/timesync.cpp | 18 ++++++++++-------- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/include/timesync.h b/include/timesync.h index 286d82e7..1f431acb 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -12,7 +12,7 @@ void timesync_init(void); void send_timesync_req(void); -int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len); +int recv_timesync_ans(uint8_t buf[], uint8_t buf_len); void process_timesync_req(void *taskparameter); void store_time_sync_req(uint32_t t_millisec); void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, timesource_t timesource); diff --git a/src/lorawan.cpp b/src/lorawan.cpp index b5e941cb..ca4425f1 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -265,10 +265,8 @@ void onEvent(ev_t ev) { #if (TIME_SYNC_LORASERVER) // timesync answer -> call timesync processor - if ((LMIC.frame[LMIC.dataBeg] >= TIMEANSWERPORT_MIN) && - (LMIC.frame[LMIC.dataBeg] <= TIMEANSWERPORT_MAX)) { - recv_timesync_ans(LMIC.frame[LMIC.dataBeg], - LMIC.frame + LMIC.dataBeg, LMIC.dataLen); + if ((LMIC.frame[LMIC.dataBeg] == TIMEPORT) { + recv_timesync_ans(LMIC.frame + LMIC.dataBeg, LMIC.dataLen); break; } #endif diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 9dffe04e..6d5eb508 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -28,7 +28,7 @@ * |< Scan Window > |< Scan Window > | ... |< Scan Window > | * |< Scan Interval >|< Scan Interval >| ... |< Scan Interval >| * |< Scan duration >| -* +* * Scan duration sets how long scanning should be going on, before starting a new scan cycle. 0 means infinite (default). * Scan window sets how much of the interval should be occupied by scanning. Should be >= BLESCANINTERVAL. * Scan interval is how long scanning should be done on each channel. BLE uses 3 channels for advertising. @@ -93,10 +93,9 @@ #define BEACONPORT 6 // beacon alarms #define BMEPORT 7 // BME680 sensor #define BATTPORT 8 // battery voltage -#define TIMEPORT 9 // time query +#define TIMEPORT 9 // time query and response #define TIMEDIFFPORT 13 // time adjust diff -#define TIMEANSWERPORT_MIN 0xA0 // time answer, start of port range -#define TIMEANSWERPORT_MAX 0xDF // time answer, end of port range +#define TIMEREQUEST_MAX_SEQNO 250 // time answer, start of port range #define SENSOR1PORT 10 // user sensor #1 #define SENSOR2PORT 11 // user sensor #2 #define SENSOR3PORT 12 // user sensor #3 diff --git a/src/timesync.cpp b/src/timesync.cpp index 09e28b3b..11ca1787 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -26,7 +26,7 @@ typedef std::chrono::duration> TaskHandle_t timeSyncReqTask = NULL; -static uint8_t time_sync_seqNo = random(TIMEANSWERPORT_MIN, TIMEANSWERPORT_MAX); +static uint8_t time_sync_seqNo = 0; static bool timeSyncPending = false; static myClock_timepoint time_sync_tx[TIME_SYNC_SAMPLES]; static myClock_timepoint time_sync_rx[TIME_SYNC_SAMPLES]; @@ -94,9 +94,10 @@ void process_timesync_req(void *taskparameter) { time_point_cast(time_sync_tx[k]); // wrap around seqNo, keeping it in time port range - time_sync_seqNo = (time_sync_seqNo < TIMEANSWERPORT_MAX) - ? time_sync_seqNo + 1 - : TIMEANSWERPORT_MIN; + time_sync_seqNo++; + if(time_sync_seqNo > TIMEREQUEST_MAX_SEQNO) { + time_sync_seqNo = 0; + } if (i < TIME_SYNC_SAMPLES - 1) { // wait until next cycle @@ -155,7 +156,9 @@ void store_time_sync_req(uint32_t timestamp) { } // process timeserver timestamp answer, called from lorawan.cpp -int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len) { +int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) { + uint8_t seq_no = buf[0]; + buf++; // if no timesync handshake is pending then exit if (!timeSyncPending) @@ -175,15 +178,14 @@ int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len) { else { // we received a probably valid time frame uint8_t k = seq_no % TIME_SYNC_SAMPLES; - uint8_t *timestamp_buf = buf+1; // 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 * timestamp_buf[4]; + uint16_t timestamp_msec = 4 * buf[4]; // pointers to 4 bytes 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 - timestamp_ptr = (uint32_t *)timestamp_buf; + timestamp_ptr = (uint32_t *)buf; // swap byte order from msb to lsb, note: this is platform dependent timestamp_sec = __builtin_bswap32(*timestamp_ptr); From 1e53a25d038dbbdd62289741d03858844b24807a Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Thu, 29 Aug 2019 14:55:31 +0200 Subject: [PATCH 14/92] typo --- src/lorawan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index ca4425f1..c4ef37e3 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -265,7 +265,7 @@ void onEvent(ev_t ev) { #if (TIME_SYNC_LORASERVER) // timesync answer -> call timesync processor - if ((LMIC.frame[LMIC.dataBeg] == TIMEPORT) { + if (LMIC.frame[LMIC.dataBeg - 1] == TIMEPORT) { recv_timesync_ans(LMIC.frame + LMIC.dataBeg, LMIC.dataLen); break; } From 2ec696649669fbdc548778967a9e4ec2fdf63fa0 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 2 Sep 2019 15:11:01 +0200 Subject: [PATCH 15/92] add OTA_TRIGGER_MAC to config --- build.py | 9 +++++---- src/ota.sample.conf | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build.py b/build.py index 28319853..52975106 100644 --- a/build.py +++ b/build.py @@ -90,10 +90,11 @@ env.Replace(BINTRAY_API_TOKEN=apitoken) # get runtime credentials and put them to compiler directive env.Append(BUILD_FLAGS=[ - u'-DWIFI_SSID=\\"' + mykeys["OTA_WIFI_SSID"] + '\\"', - u'-DWIFI_PASS=\\"' + mykeys["OTA_WIFI_PASS"] + '\\"', - u'-DBINTRAY_USER=\\"' + mykeys["BINTRAY_USER"] + '\\"', - u'-DBINTRAY_REPO=\\"' + mykeys["BINTRAY_REPO"] + '\\"', + u'-DWIFI_SSID=\\"' + mykeys["OTA_WIFI_SSID"] + '\\"', + u'-DWIFI_PASS=\\"' + mykeys["OTA_WIFI_PASS"] + '\\"', + u'-DOTA_TRIGGER_MAC=\\"' + mykeys["OTA_TRIGGER_MAC"] + '\\"', + u'-DBINTRAY_USER=\\"' + mykeys["BINTRAY_USER"] + '\\"', + u'-DBINTRAY_REPO=\\"' + mykeys["BINTRAY_REPO"] + '\\"', u'-DBINTRAY_PACKAGE=\\"' + package + '\\"', u'-DARDUINO_LMIC_PROJECT_CONFIG_H=' + lmicconfig, u'-I \"' + srcdir + '\"' diff --git a/src/ota.sample.conf b/src/ota.sample.conf index a10d79dc..fa698c31 100644 --- a/src/ota.sample.conf +++ b/src/ota.sample.conf @@ -1,6 +1,7 @@ [ota] OTA_WIFI_SSID = MyHomeWifi OTA_WIFI_PASS = FooBar42! +OTA_TRIGGER_MAC = FFFFFFFF [bintray] BINTRAY_USER = MyBintrayUser From e92bcbd8b1fabebae938b3bc0e373d7beea9b350 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 2 Sep 2019 15:11:52 +0200 Subject: [PATCH 16/92] setup macsniff with ota trigger mac --- include/macsniff.h | 1 + src/macsniff.cpp | 12 ++++++++++++ src/main.cpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/include/macsniff.h b/include/macsniff.h index d41fc787..663a7749 100644 --- a/include/macsniff.h +++ b/include/macsniff.h @@ -12,6 +12,7 @@ #define MAC_SNIFF_WIFI 0 #define MAC_SNIFF_BLE 1 +void macsniff_setup(void); uint16_t get_salt(void); uint64_t macConvert(uint8_t *paddr); bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type); diff --git a/src/macsniff.cpp b/src/macsniff.cpp index 0b00e7c1..fdb37273 100644 --- a/src/macsniff.cpp +++ b/src/macsniff.cpp @@ -6,10 +6,22 @@ #include "vendor_array.h" #endif +#include +#include + // Local logging tag static const char TAG[] = __FILE__; uint16_t salt; +uint64_t fota_trigger_mac; + +void macsniff_setup() { + std::stringstream ss; + ss << std::hex << OTA_TRIGGER_MAC; + ESP_LOGI(TAG, "OTA_TRIGGER_MAC %X", OTA_TRIGGER_MAC); + ss >> fota_trigger_mac; + std::cout << static_cast(fota_trigger_mac) << std::endl; +} uint16_t get_salt(void) { salt = (uint16_t)random(65536); // get new 16bit random for salting hashes diff --git a/src/main.cpp b/src/main.cpp index 2a7aab1a..a8e50ea5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -444,6 +444,8 @@ void setup() { // show compiled features ESP_LOGI(TAG, "Features:%s", features); + macsniff_setup(); + uart_setup(); } // setup() From a806c5e4637a29cadb91657403e1f81e3e340707 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 2 Sep 2019 15:12:22 +0200 Subject: [PATCH 17/92] recognize ota trigger mac when sniffing for new macs in wifi environment --- src/macsniff.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/macsniff.cpp b/src/macsniff.cpp index fdb37273..2ab8740e 100644 --- a/src/macsniff.cpp +++ b/src/macsniff.cpp @@ -94,6 +94,25 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { // Count only if MAC was not yet seen if (added) { + ESP_LOGD(TAG, "new Mac: %x:%x:%x:%x:%x:%x", + paddr[0], + paddr[1], + paddr[2], + paddr[3], + paddr[4], + paddr[5] + ); + // is newly found MAC the OTA trigger? + uint64_t addr48 = (((uint64_t)paddr[3]) | ((uint64_t)paddr[2] << 8) | + ((uint64_t)paddr[1] << 16) | ((uint64_t)paddr[0] << 24)); + if((int)(addr48-fota_trigger_mac) == 0) + { + ESP_LOGI(TAG, "OTA-MAC found, Update triggered"); + // initiate OTA update + uint8_t cmd[2] = {9, 9}; + rcommand(cmd, 2); + } + // increment counter and one blink led if (sniff_type == MAC_SNIFF_WIFI) { macs_wifi++; // increment Wifi MACs counter @@ -146,4 +165,4 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { // True if MAC WiFi/BLE was new return added; // function returns bool if a new and unique Wifi or BLE mac was // counted (true) or not (false) -} \ No newline at end of file +} From 2530bd4235446ceb9983e6daddc0e08be2930c47 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 2 Sep 2019 16:56:50 +0200 Subject: [PATCH 18/92] remove unneeded logging --- src/macsniff.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/macsniff.cpp b/src/macsniff.cpp index 2ab8740e..079c2f8c 100644 --- a/src/macsniff.cpp +++ b/src/macsniff.cpp @@ -18,7 +18,6 @@ uint64_t fota_trigger_mac; void macsniff_setup() { std::stringstream ss; ss << std::hex << OTA_TRIGGER_MAC; - ESP_LOGI(TAG, "OTA_TRIGGER_MAC %X", OTA_TRIGGER_MAC); ss >> fota_trigger_mac; std::cout << static_cast(fota_trigger_mac) << std::endl; } From 004444dea3d67034ff366a28571d75cad009dd5d Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 2 Sep 2019 16:55:14 +0200 Subject: [PATCH 19/92] correct logging level for error --- src/timesync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timesync.cpp b/src/timesync.cpp index 11ca1787..66bbd06c 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -249,7 +249,7 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, struct timeval tv; struct timezone tz; if(gettimeofday(&tv, &tz) != 0) { - ESP_LOGI(TAG, "ERROR gettimeofday"); + ESP_LOGE(TAG, "ERROR gettimeofday"); } struct timeval beforeTime = tv; From 592c9d6edea5d2267d2cb6f8bef2c15f43ee1682 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 2 Sep 2019 16:55:29 +0200 Subject: [PATCH 20/92] log sent timediff --- src/timesync.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/timesync.cpp b/src/timesync.cpp index 66bbd06c..be752fac 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -282,6 +282,7 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec, 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); From fc2997c9fd87f4d7b67af5a1492e00ca1c09d5c2 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Mon, 2 Sep 2019 16:56:06 +0200 Subject: [PATCH 21/92] start timediffseq at -1, so first syncing can finish --- src/timesync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timesync.cpp b/src/timesync.cpp index be752fac..e51454eb 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -26,7 +26,7 @@ typedef std::chrono::duration> TaskHandle_t timeSyncReqTask = NULL; -static uint8_t time_sync_seqNo = 0; +static uint8_t time_sync_seqNo = -1; static bool timeSyncPending = false; static myClock_timepoint time_sync_tx[TIME_SYNC_SAMPLES]; static myClock_timepoint time_sync_rx[TIME_SYNC_SAMPLES]; From 2622c0d0dede55f2b214c6f0c4f44069c41ffad0 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Wed, 25 Sep 2019 15:00:52 +0200 Subject: [PATCH 22/92] sanitize compiler warning power.cpp --- src/power.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/power.cpp b/src/power.cpp index 83748286..6b7f1f5e 100644 --- a/src/power.cpp +++ b/src/power.cpp @@ -207,15 +207,17 @@ uint16_t read_voltage() { #ifdef BAT_MEASURE_ADC // multisample ADC uint32_t adc_reading = 0; +#ifndef BAT_MEASURE_ADC_UNIT // ADC1 + for (int i = 0; i < NO_OF_SAMPLES; i++) { + adc_reading += adc1_get_raw(adc_channel); + } +#else // ADC2 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 } +#endif adc_reading /= NO_OF_SAMPLES; // Convert ADC reading to voltage in mV voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_characs); From cb67e368ba63a0200bbc46f71a98ec8fb78a19a2 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 27 Sep 2019 12:41:14 +0200 Subject: [PATCH 23/92] add countermode to paxcounter.conf --- src/configmanager.cpp | 2 +- src/paxcounter.conf | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 5b235f70..c629d617 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -20,7 +20,7 @@ void defaultConfig() { 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.countermode = COUNTERMODE; // 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 = diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 40852f59..38feccc3 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -14,6 +14,7 @@ // Payload send cycle and encoding #define SENDCYCLE 30 // payload send cycle [seconds/2], 0 .. 255 #define PAYLOAD_ENCODER 2 // payload encoder: 1=Plain, 2=Packed, 3=Cayenne LPP dynamic, 4=Cayenne LPP packed +#define COUNTERMODE 0 // 0=cyclic, 1=cumulative, 2=cyclic confirmed // Set this to include BLE counting and vendor filter functions, or to switch off WIFI counting #define VENDORFILTER 1 // set to 0 if you want to count things, not people From 0f9e2dfd63ed7c9eea82c28b0c3bdb35fb224d02 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 27 Sep 2019 12:47:00 +0200 Subject: [PATCH 24/92] new oled driver (experimental) --- include/display.h | 5 +- include/ota.h | 7 +- platformio.ini | 5 +- src/display.cpp | 257 +++++++++++++++++--------------------- src/hal/ecopower.h | 4 +- src/hal/generic.h | 2 +- src/hal/heltec.h | 2 +- src/hal/heltecv2.h | 2 +- src/hal/lolin32litelora.h | 4 +- src/hal/lolin32lora.h | 4 +- src/hal/octopus32.h | 4 +- src/hal/ttgobeam.h | 4 +- src/hal/ttgobeam10.h | 4 +- src/hal/ttgofox.h | 4 +- src/hal/ttgov1.h | 2 +- src/hal/ttgov2.h | 4 +- src/hal/ttgov21new.h | 4 +- src/hal/ttgov21old.h | 4 +- src/hal/wemos32oled.h | 4 +- src/ota.cpp | 84 ++++++------- src/paxcounter.conf | 2 +- 21 files changed, 190 insertions(+), 222 deletions(-) diff --git a/include/display.h b/include/display.h index bbaa568c..90ea3f38 100644 --- a/include/display.h +++ b/include/display.h @@ -1,16 +1,13 @@ #ifndef _DISPLAY_H #define _DISPLAY_H -#include #include "cyclic.h" extern uint8_t DisplayIsOn; -extern HAS_DISPLAY u8x8; - void init_display(const char *Productname, const char *Version); void refreshTheDisplay(bool nextPage = false); void draw_page(time_t t, uint8_t page); -void DisplayKey(const uint8_t *key, uint8_t len, bool lsb); +void dp_printf(int x, int y, int font, int inv, const char *format, ...); #endif \ No newline at end of file diff --git a/include/ota.h b/include/ota.h index 59bf876c..cec28750 100644 --- a/include/ota.h +++ b/include/ota.h @@ -4,6 +4,7 @@ #ifdef USE_OTA #include "globals.h" +#include #include #include #include @@ -14,11 +15,9 @@ int do_ota_update(); void start_ota_update(); int version_compare(const String v1, const String v2); -void display(const uint8_t row, const std::string status, - const std::string msg); -#ifdef HAS_DISPLAY +void ota_display(const uint8_t row, const std::string status, + const std::string msg); void show_progress(unsigned long current, unsigned long size); -#endif #endif // USE_OTA diff --git a/platformio.ini b/platformio.ini index adfcc3e1..ded8baf9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,7 +43,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 = 1.8.34 +release_version = 1.8.4 ; 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 @@ -57,7 +57,8 @@ upload_speed = 115200 lib_deps_lora = MCCI LoRaWAN LMIC library@>=3.0.99 lib_deps_display = - U8g2@>=2.26.13 + ss_oled@>=2.1.1 + BitBang_I2C@>=1.2.0 lib_deps_matrix_display = https://github.com/Seeed-Studio/Ultrathin_LED_Matrix.git lib_deps_rgbled = diff --git a/src/display.cpp b/src/display.cpp index b89f551d..8db7eefa 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -26,11 +26,11 @@ line 7: y = LMIC event message; ab = payload queue length // Basic Config #include "globals.h" +#include #include // needed for reading ESP32 chip attributes #define DISPLAY_PAGES (4) // number of display pages - -HAS_DISPLAY u8x8(MY_OLED_RST, MY_OLED_SCL, MY_OLED_SDA); +#define USE_BACKBUFFER // for display library // helper arry for converting month values to text const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -38,82 +38,63 @@ const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", uint8_t DisplayIsOn = 0; -// helper function, prints a hex key on display -void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) { - const uint8_t *p; - for (uint8_t i = 0; i < len; i++) { - p = lsb ? key + len - i - 1 : key + i; - u8x8.printf("%02X", *p); - } - u8x8.printf("\n"); -} - void init_display(const char *Productname, const char *Version) { // block i2c bus access if (!I2C_MUTEX_LOCK()) ESP_LOGV(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0); else { - // show startup screen - uint8_t buf[32]; - u8x8.begin(); - u8x8.setFont(u8x8_font_chroma48medium8_r); - u8x8.clear(); - u8x8.setFlipMode(0); - u8x8.setInverseFont(1); - u8x8.draw2x2String(0, 0, Productname); - u8x8.setInverseFont(0); - u8x8.draw2x2String(2, 2, Productname); - delay(500); - u8x8.clear(); - u8x8.setFlipMode(1); - u8x8.setInverseFont(1); - u8x8.draw2x2String(0, 0, Productname); - u8x8.setInverseFont(0); - u8x8.draw2x2String(2, 2, Productname); - delay(500); - u8x8.setFlipMode(0); - u8x8.clear(); - -#ifdef DISPLAY_FLIP - u8x8.setFlipMode(1); + // init display +#ifndef DISPLAY_FLIP + oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 400000L); +#else + oledInit(OLED_128x64, ANGLE_FLIPY, false, -1, -1, 400000L); #endif -// Display chip information + // clear display + oledFill(0, 1); + + // show startup screen + // to come -> display .bmp file with logo + +// show chip information #if (VERBOSE) esp_chip_info_t chip_info; esp_chip_info(&chip_info); - u8x8.printf("ESP32 %d cores\nWiFi%s%s\n", chip_info.cores, - (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", - (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); - u8x8.printf("ESP Rev.%d\n", chip_info.revision); - u8x8.printf("%dMB %s Flash\n", spi_flash_get_chip_size() / (1024 * 1024), - (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." - : "ext."); + dp_printf(0, 0, 0, 0, "ESP32 %d cores", chip_info.cores); + dp_printf(0, 2, 0, 0, "Chip Rev.%d", chip_info.revision); + dp_printf(0, 1, 0, 0, "WiFi%s%s", + (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); + dp_printf(0, 3, 0, 0, "%dMB %s Flash", + spi_flash_get_chip_size() / (1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext."); #endif // VERBOSE - u8x8.print(Productname); - u8x8.print(" v"); - u8x8.println(PROGVERSION); - #if (HAS_LORA) - u8x8.println("DEVEUI:"); + uint8_t buf[34]; + const uint8_t *p; os_getDevEui((u1_t *)buf); - DisplayKey(buf, 8, true); - delay(3000); + dp_printf(0, 5, 0, 0, "DEVEUI:"); + for (uint8_t i = 0; i < 8; i++) { + p = buf + 7 - i; + dp_printf(i * 16, 6, 0, 0, "%02X", *p); + } #endif // HAS_LORA - u8x8.clear(); - u8x8.setPowerSave(!cfg.screenon); // set display off if disabled - u8x8.draw2x2String(0, 0, "PAX:0"); + + dp_printf(0, 4, 0, 0, "Software v%s", PROGVERSION); + delay(3000); + + oledFill(0, 1); + oledPower(cfg.screenon); // set display off if disabled + dp_printf(0, 0, 1, 0, "PAX:0"); #if (BLECOUNTER) - u8x8.setCursor(0, 3); - u8x8.printf("BLTH:0"); + dp_printf(0, 3, 0, 0, "BLTH:0"); #endif - u8x8.setCursor(0, 4); - u8x8.printf("WIFI:0"); - u8x8.setCursor(0, 5); - u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%d", cfg.rssilimit); + dp_printf(0, 4, 0, 0, "WIFI:0"); + dp_printf(0, 5, 0, 0, !cfg.rssilimit ? "RLIM:off " : "RLIM:%d", + cfg.rssilimit); I2C_MUTEX_UNLOCK(); // release i2c bus access } // mutex @@ -137,12 +118,12 @@ void refreshTheDisplay(bool nextPage) { // set display on/off according to current device configuration if (DisplayIsOn != cfg.screenon) { DisplayIsOn = cfg.screenon; - u8x8.setPowerSave(!cfg.screenon); + oledPower(cfg.screenon); } if (nextPage) { DisplayPage = (DisplayPage >= DISPLAY_PAGES - 1) ? 0 : (DisplayPage + 1); - u8x8.clear(); + oledFill(0, 1); } draw_page(t, DisplayPage); @@ -161,11 +142,8 @@ void draw_page(time_t t, uint8_t page) { #endif // update counter (lines 0-1) - snprintf( - buff, sizeof(buff), "PAX:%-4d", - (int)macs.size()); // convert 16-bit MAC counter to decimal counter value - u8x8.draw2x2String(0, 0, - buff); // display number on unique macs total Wifi + BLE + dp_printf(0, 0, FONT_STRETCHED, 0, "PAX:%-4d", + (int)macs.size()); // display number of unique macs total Wifi + BLE switch (page % DISPLAY_PAGES) { @@ -178,139 +156,108 @@ void draw_page(time_t t, uint8_t page) { // update Battery status (line 2) #if (defined BAT_MEASURE_ADC || defined HAS_PMU) - u8x8.setCursor(0, 2); if (batt_voltage == 0xffff) - u8x8.printf("B:USB "); + dp_printf(0, 2, 0, 0, "%s", "B:USB "); else - u8x8.printf("B:%.2fV", batt_voltage / 1000.0); + dp_printf(0, 2, 0, 0, "B:%.2fV", batt_voltage / 1000.0); #endif // update GPS status (line 2) #if (HAS_GPS) - u8x8.setCursor(9, 2); if (gps.location.age() < 1500) // if no fix then display Sats value inverse - u8x8.printf("Sats:%.2d", gps.satellites.value()); - else { - u8x8.setInverseFont(1); - u8x8.printf("Sats:%.2d", gps.satellites.value()); - u8x8.setInverseFont(0); - } + dp_printf(72, 2, 0, 0, "Sats:%.2d", gps.satellites.value()); + else + dp_printf(72, 2, 0, 1, "Sats:%.2d", gps.satellites.value()); #endif - // update bluetooth counter + LoRa SF (line 3) + // update bluetooth counter + LoRa SF (line 3) #if (BLECOUNTER) - u8x8.setCursor(0, 3); if (cfg.blescan) - u8x8.printf("BLTH:%-5d", macs_ble); + dp_printf(0, 3, 0, 0, "BLTH:%-5d", macs_ble); else - u8x8.printf("%s", "BLTH:off"); + dp_printf(0, 3, 0, 0, "%s", "BLTH:off"); #endif #if (HAS_LORA) - u8x8.setCursor(12, 3); - if (!cfg.adrmode) // if ADR=off then display SF value inverse - u8x8.setInverseFont(1); - u8x8.printf("%-4s", getSfName(updr2rps(LMIC.datarate))); - if (!cfg.adrmode) // switch off inverse if it was turned on - u8x8.setInverseFont(0); + if (cfg.adrmode) + dp_printf(96, 3, 0, 0, "%-4s", getSfName(updr2rps(LMIC.datarate))); + else // if ADR=off then display SF value inverse + dp_printf(96, 3, 0, 1, "%-4s", getSfName(updr2rps(LMIC.datarate))); #endif // HAS_LORA // line 4: update wifi counter + channel display - u8x8.setCursor(0, 4); - u8x8.printf("WIFI:%-5d", macs_wifi); - u8x8.setCursor(11, 4); - u8x8.printf("ch:%02d", channel); + dp_printf(0, 4, 0, 0, "WIFI:%-5d", macs_wifi); + dp_printf(88, 4, 0, 0, "ch:%02d", channel); // line 5: update RSSI limiter status & free memory display - u8x8.setCursor(0, 5); - u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%-4d", cfg.rssilimit); - u8x8.setCursor(10, 5); - u8x8.printf("%4dKB", getFreeRAM() / 1024); + dp_printf(0, 5, 0, 0, !cfg.rssilimit ? "RLIM:off " : "RLIM:%-4d", + cfg.rssilimit); + dp_printf(80, 5, 0, 0, "%4dKB", getFreeRAM() / 1024); // line 6: update time-of-day or LoRa status display - u8x8.setCursor(0, 6); #if (TIME_SYNC_INTERVAL) // we want a systime display instead LoRa status timeState = TimePulseTick ? ' ' : timeSetSymbols[timeSource]; TimePulseTick = false; // display inverse timeState if clock controller is enabled #if (defined HAS_DCF77) || (defined HAS_IF482) - u8x8.printf("%02d:%02d:%02d", hour(t), minute(t), second(t)); - u8x8.setInverseFont(1); - u8x8.printf("%c", timeState); - u8x8.setInverseFont(0); + dp_printf(0, 6, FONT_SMALL, 0, "%02d:%02d:%02d", hour(t), minute(t), + second(t)); + dp_printf(56, 6, FONT_SMALL, 1, "%c", timeState); #else - u8x8.printf("%02d:%02d:%02d%c", hour(t), minute(t), second(t), timeState); + dp_printf(0, 6, FONT_SMALL, 0, "%02d:%02d:%02d%c", hour(t), minute(t), + second(t), timeState); #endif // HAS_DCF77 || HAS_IF482 if (timeSource != _unsynced) - u8x8.printf(" %2d.%3s", day(t), printmonth[month(t)]); + dp_printf(72, 6, FONT_SMALL, 0, " %2d.%3s%4s", day(t), + printmonth[month(t)], year(t)); #endif // TIME_SYNC_INTERVAL #if (HAS_LORA) // line 7: update LMiC event display - u8x8.setCursor(0, 7); - u8x8.printf("%-14s", lmic_event_msg); + dp_printf(0, 7, FONT_SMALL, 0, "%-14s", lmic_event_msg); // update LoRa send queue display msgWaiting = uxQueueMessagesWaiting(LoraSendQueue); if (msgWaiting) { sprintf(buff, "%2d", msgWaiting); - u8x8.setCursor(14, 7); - u8x8.printf("%-2s", msgWaiting == SEND_QUEUE_SIZE ? "<>" : buff); + dp_printf(112, 7, FONT_SMALL, 0, "%-2s", + msgWaiting == SEND_QUEUE_SIZE ? "<>" : buff); } else - u8x8.printf(" "); + dp_printf(112, 7, FONT_SMALL, 0, " "); #endif // HAS_LORA break; // page0 case 1: - - // line 4-5: update time-of-day - snprintf(buff, sizeof(buff), "%02d:%02d:%02d", hour(t), minute(t), - second(t)); - u8x8.draw2x2String(0, 4, buff); - + dp_printf(0, 4, FONT_STRETCHED, 0, "%02d:%02d:%02d", hour(t), minute(t), + second(t)); break; // page1 case 2: - // update counter (lines 0-1) - snprintf( - buff, sizeof(buff), "PAX:%-4d", - (int) - macs.size()); // convert 16-bit MAC counter to decimal counter value - u8x8.draw2x2String(0, 0, - buff); // display number on unique macs total Wifi + BLE - #if (HAS_GPS) if (gps.location.age() < 1500) { // line 5: clear "No fix" if (wasnofix) { - snprintf(buff, sizeof(buff), " "); - u8x8.draw2x2String(2, 5, buff); + dp_printf(16, 5, FONT_STRETCHED, 0, " "); wasnofix = false; } // line 3-4: GPS latitude - snprintf(buff, sizeof(buff), "%c%07.4f", - gps.location.rawLat().negative ? 'S' : 'N', gps.location.lat()); - u8x8.draw2x2String(0, 3, buff); + dp_printf(0, 3, FONT_STRETCHED, 0, "%c%07.4f", + gps.location.rawLat().negative ? 'S' : 'N', gps.location.lat()); // line 6-7: GPS longitude - snprintf(buff, sizeof(buff), "%c%07.4f", - gps.location.rawLat().negative ? 'W' : 'E', gps.location.lng()); - u8x8.draw2x2String(0, 6, buff); + dp_printf(0, 6, FONT_STRETCHED, 0, "%c%07.4f", + gps.location.rawLat().negative ? 'W' : 'E', gps.location.lng()); } else { - snprintf(buff, sizeof(buff), "No fix"); - u8x8.setInverseFont(1); - u8x8.draw2x2String(2, 5, buff); - u8x8.setInverseFont(0); + dp_printf(16, 5, FONT_STRETCHED, 1, "No fix"); wasnofix = true; } #else - snprintf(buff, sizeof(buff), "No GPS"); - u8x8.draw2x2String(2, 5, buff); + dp_printf(16, 5, FONT_STRETCHED, 1, "No GPS"); #endif break; // page2 @@ -319,22 +266,18 @@ void draw_page(time_t t, uint8_t page) { #if (HAS_BME) // line 2-3: Temp - snprintf(buff, sizeof(buff), "TMP:%-2.1f", bme_status.temperature); - u8x8.draw2x2String(0, 2, buff); + dp_printf(0, 2, FONT_STRETCHED, 0, "TMP:%-2.1f", bme_status.temperature); // line 4-5: Hum - snprintf(buff, sizeof(buff), "HUM:%-2.1f", bme_status.humidity); - u8x8.draw2x2String(0, 4, buff); + dp_printf(0, 4, FONT_STRETCHED, 0, "HUM:%-2.1f", bme_status.humidity); #ifdef HAS_BME680 // line 6-7: IAQ - snprintf(buff, sizeof(buff), "IAQ:%-3.0f", bme_status.iaq); - u8x8.draw2x2String(0, 6, buff); + dp_printf(0, 6, FONT_STRETCHED, 0, "IAQ:%-3.0f", bme_status.iaq); #endif #else - snprintf(buff, sizeof(buff), "No BME"); - u8x8.draw2x2String(2, 5, buff); + dp_printf(16, 5, FONT_STRETCHED, 1, "No BME"); #endif break; // page3 @@ -346,4 +289,34 @@ void draw_page(time_t t, uint8_t page) { } // draw_page +// display print helper function + +void dp_printf(int x, int y, int font, int inv, const char *format, ...) { + char loc_buf[64]; + char *temp = loc_buf; + va_list arg; + va_list copy; + va_start(arg, format); + va_copy(copy, arg); + int len = vsnprintf(temp, sizeof(loc_buf), format, copy); + va_end(copy); + if (len < 0) { + va_end(arg); + return; + }; + if (len >= sizeof(loc_buf)) { + temp = (char *)malloc(len + 1); + if (temp == NULL) { + va_end(arg); + return; + } + len = vsnprintf(temp, len + 1, format, arg); + } + va_end(arg); + oledWriteString(0, x, y, temp, font, inv, 1); + if (temp != loc_buf) { + free(temp); + } +} + #endif // HAS_DISPLAY \ No newline at end of file diff --git a/src/hal/ecopower.h b/src/hal/ecopower.h index 4f4b303a..deca82d7 100644 --- a/src/hal/ecopower.h +++ b/src/hal/ecopower.h @@ -12,7 +12,7 @@ //#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_DISPLAY 1 //#define DISPLAY_FLIP 1 // use if display is rotated #define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7 #define BAT_VOLTAGE_DIVIDER ((82.0+220.0)/82.0) // 82k + 220k 1% @@ -29,7 +29,7 @@ // Pins for I2C interface of OLED Display #define MY_OLED_SDA SDA #define MY_OLED_SCL SCL -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN // Settings for on board DS3231 RTC chip // note: to use RTC_INT, capacitor 100nF next to red LED must be removed to sharpen interrupt signal slope diff --git a/src/hal/generic.h b/src/hal/generic.h index c606e5ba..909bef38 100644 --- a/src/hal/generic.h +++ b/src/hal/generic.h @@ -44,7 +44,7 @@ #define BOARD_HAS_PSRAM // use if board has external PSRAM #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_DISPLAY 1 //#define DISPLAY_FLIP 1 // use if display is rotated #define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7 #define BAT_VOLTAGE_DIVIDER 2 // voltage divider 100k/100k on board diff --git a/src/hal/heltec.h b/src/hal/heltec.h index 465793a1..4432c9a3 100644 --- a/src/hal/heltec.h +++ b/src/hal/heltec.h @@ -16,7 +16,7 @@ #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board +#define HAS_DISPLAY 1 // OLED-Display on board #define HAS_LED LED_BUILTIN // white LED on board #define HAS_BUTTON KEY_BUILTIN // button "PROG" on board diff --git a/src/hal/heltecv2.h b/src/hal/heltecv2.h index adb74981..96024e38 100644 --- a/src/hal/heltecv2.h +++ b/src/hal/heltecv2.h @@ -16,7 +16,7 @@ #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board +#define HAS_DISPLAY 1 // OLED-Display on board #define HAS_LED LED_BUILTIN // white LED on board #define HAS_BUTTON KEY_BUILTIN // button "PROG" on board diff --git a/src/hal/lolin32litelora.h b/src/hal/lolin32litelora.h index 11f3f156..07af6837 100644 --- a/src/hal/lolin32litelora.h +++ b/src/hal/lolin32litelora.h @@ -13,7 +13,7 @@ // disable brownout detection (avoid unexpected reset on some boards) #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board +#define HAS_DISPLAY 1 // OLED-Display on board //#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 @@ -37,7 +37,7 @@ // Pins for I2C interface of OLED Display #define MY_OLED_SDA (14) #define MY_OLED_SCL (12) -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN // I2C config for Microchip 24AA02E64 DEVEUI unique address #define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64 diff --git a/src/hal/lolin32lora.h b/src/hal/lolin32lora.h index a79b0d84..a14c9605 100644 --- a/src/hal/lolin32lora.h +++ b/src/hal/lolin32lora.h @@ -13,7 +13,7 @@ // disable brownout detection (avoid unexpected reset on some boards) #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board +#define HAS_DISPLAY 1 // OLED-Display on board //#define DISPLAY_FLIP 1 // uncomment this for rotated display #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 @@ -39,7 +39,7 @@ // Pins for I2C interface of OLED Display #define MY_OLED_SDA (21) #define MY_OLED_SCL (22) -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN // I2C config for Microchip 24AA02E64 DEVEUI unique address #define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64 diff --git a/src/hal/octopus32.h b/src/hal/octopus32.h index d245a8c2..f34f609b 100644 --- a/src/hal/octopus32.h +++ b/src/hal/octopus32.h @@ -41,10 +41,10 @@ #define LORA_IO2 LMIC_UNUSED_PIN // Pins for I2C interface of OLED Display -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // U8X8_SSD1306_128X32_UNIVISION_SW_I2C // +#define HAS_DISPLAY 1 //#define DISPLAY_FLIP 1 // uncomment this for rotated display #define MY_OLED_SDA (23) #define MY_OLED_SCL (22) -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN #endif diff --git a/src/hal/ttgobeam.h b/src/hal/ttgobeam.h index f8be7ee0..a4d81926 100644 --- a/src/hal/ttgobeam.h +++ b/src/hal/ttgobeam.h @@ -33,10 +33,10 @@ #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 +#define HAS_DISPLAY 1 #define MY_OLED_SDA SDA #define MY_OLED_SCL SCL -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN //#define DISPLAY_FLIP 1 // use if display is rotated // user defined sensors (if connected) diff --git a/src/hal/ttgobeam10.h b/src/hal/ttgobeam10.h index fa0b3ffa..35bd78da 100644 --- a/src/hal/ttgobeam10.h +++ b/src/hal/ttgobeam10.h @@ -20,10 +20,10 @@ User, long press -> send LORA message Reset -> reset device */ -//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_DISPLAY 1 #define MY_OLED_SDA SDA #define MY_OLED_SCL SCL -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN //#define DISPLAY_FLIP 1 // use if display is rotated #define HAS_LORA 1 // comment out if device shall not send data via LoRa diff --git a/src/hal/ttgofox.h b/src/hal/ttgofox.h index 94b2b60f..8a7e3a9c 100644 --- a/src/hal/ttgofox.h +++ b/src/hal/ttgofox.h @@ -10,7 +10,7 @@ #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 // HPD13A LoRa SoC -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_DISPLAY 1 #define HAS_LED NOT_A_PIN // green on board LED is useless, is GPIO25, which switches power for Lora+Display #define EXT_POWER_SW GPIO_NUM_25 // switches power for LoRa chip @@ -23,7 +23,7 @@ // Pins for I2C interface of OLED Display #define MY_OLED_SDA (21) #define MY_OLED_SCL (22) -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN // Settings for on board DS3231 RTC chip #define HAS_RTC MY_OLED_SDA, MY_OLED_SCL // SDA, SCL diff --git a/src/hal/ttgov1.h b/src/hal/ttgov1.h index fddc3ef5..1aaf20c3 100644 --- a/src/hal/ttgov1.h +++ b/src/hal/ttgov1.h @@ -12,7 +12,7 @@ #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board +#define HAS_DISPLAY 1 // OLED-Display on board //#define DISPLAY_FLIP 1 // uncomment this for rotated display #define HAS_LED LED_BUILTIN #define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW diff --git a/src/hal/ttgov2.h b/src/hal/ttgov2.h index 54f1657a..e5e784f3 100644 --- a/src/hal/ttgov2.h +++ b/src/hal/ttgov2.h @@ -12,7 +12,7 @@ #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 // HPD13A LoRa SoC -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_DISPLAY 1 //#define DISPLAY_FLIP 1 // uncomment this for rotated display #define HAS_LED NOT_A_PIN // on-board LED is wired to SCL (used by display) therefore totally useless @@ -22,7 +22,7 @@ // Pins for I2C interface of OLED Display #define MY_OLED_SDA (21) #define MY_OLED_SCL (22) -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN // Pins for LORA chip SPI interface come from board file, we need some // additional definitions for LMIC diff --git a/src/hal/ttgov21new.h b/src/hal/ttgov21new.h index c50869b2..4c1cd4fc 100644 --- a/src/hal/ttgov21new.h +++ b/src/hal/ttgov21new.h @@ -20,7 +20,7 @@ //#define HAS_BME 1 // Enable BME sensors in general //#define HAS_BME280 GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_DISPLAY 1 #define HAS_LED (25) // green on board LED #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 @@ -28,7 +28,7 @@ // Pins for I2C interface of OLED Display #define MY_OLED_SDA (21) #define MY_OLED_SCL (22) -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN // Pins for LORA chip SPI interface, reset line and interrupt lines #define LORA_SCK (5) diff --git a/src/hal/ttgov21old.h b/src/hal/ttgov21old.h index 0a7c386c..a19887ca 100644 --- a/src/hal/ttgov21old.h +++ b/src/hal/ttgov21old.h @@ -19,7 +19,7 @@ #define HAS_LED NOT_A_PIN // no usable LED on board #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_DISPLAY 1 //#define DISPLAY_FLIP 1 // rotated display //#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 @@ -27,7 +27,7 @@ // Pins for I2C interface of OLED Display #define MY_OLED_SDA (21) #define MY_OLED_SCL (22) -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN // Pins for LORA chip SPI interface, reset line and interrupt lines #define LORA_SCK (5) diff --git a/src/hal/wemos32oled.h b/src/hal/wemos32oled.h index 3b59e450..2955fbaa 100644 --- a/src/hal/wemos32oled.h +++ b/src/hal/wemos32oled.h @@ -9,10 +9,10 @@ #define HAS_LED NOT_A_PIN // no LED -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define HAS_DISPLAY 1 #define MY_OLED_SDA (5) #define MY_OLED_SCL (4) -#define MY_OLED_RST U8X8_PIN_NONE +#define MY_OLED_RST NOT_A_PIN #define DISPLAY_FLIP 1 // use if display is rotated #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature diff --git a/src/ota.cpp b/src/ota.cpp index fc1662bc..e05b6f8f 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -49,24 +49,24 @@ void start_ota_update() { switch_LED(LED_ON); #ifdef HAS_DISPLAY - u8x8.begin(); - u8x8.setFont(u8x8_font_chroma48medium8_r); - u8x8.clear(); -#ifdef DISPLAY_FLIP - u8x8.setFlipMode(1); -#endif - u8x8.setInverseFont(1); - u8x8.print("SOFTWARE UPDATE \n"); - u8x8.setInverseFont(0); - u8x8.print("WiFi connect ..\n"); - u8x8.print("Has Update? ..\n"); - u8x8.print("Fetching ..\n"); - u8x8.print("Downloading ..\n"); - u8x8.print("Rebooting .."); + +// init display +#ifndef DISPLAY_FLIP + int rc = oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 100000L); +#else + int rc = oledInit(OLED_128x64, ANGLE_FLIPY, false, -1, -1, 100000L); #endif + oledFill(0, 1); + dp_printf(0, 0, 0, 1, "SOFTWARE UPDATE"); + dp_printf(0, 1, 0, 0, "WiFi connect .."); + dp_printf(0, 2, 0, 0, "Has Update? .."); + dp_printf(0, 3, 0, 0, "Fetching .."); + dp_printf(0, 4, 0, 0, "Downloading .."); + dp_printf(0, 5, 0, 0, "Rebooting .."); + ESP_LOGI(TAG, "Starting Wifi OTA update"); - display(1, "**", WIFI_SSID); + ota_display(1, "**", WIFI_SSID); WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASS); @@ -81,7 +81,7 @@ void start_ota_update() { if (WiFi.status() == WL_CONNECTED) { // we now have wifi connection and try to do an OTA over wifi update ESP_LOGI(TAG, "Connected to %s", WIFI_SSID); - display(1, "OK", "WiFi connected"); + ota_display(1, "OK", "WiFi connected"); // do a number of tries to update firmware limited by OTA_MAX_TRY uint8_t j = OTA_MAX_TRY; while ((j--) && (ret > 0)) { @@ -97,13 +97,13 @@ void start_ota_update() { // wifi did not connect ESP_LOGI(TAG, "Could not connect to %s", WIFI_SSID); - display(1, " E", "no WiFi connect"); + ota_display(1, " E", "no WiFi connect"); delay(5000); end: switch_LED(LED_OFF); ESP_LOGI(TAG, "Rebooting to %s firmware", (ret == 0) ? "new" : "current"); - display(5, "**", ""); // mark line rebooting + ota_display(5, "**", ""); // mark line rebooting delay(5000); ESP.restart(); @@ -119,7 +119,7 @@ int do_ota_update() { // Fetch the latest firmware version ESP_LOGI(TAG, "Checking latest firmware version on server"); - display(2, "**", "checking version"); + ota_display(2, "**", "checking version"); if (WiFi.status() != WL_CONNECTED) return 1; @@ -128,23 +128,23 @@ int do_ota_update() { if (latest.length() == 0) { ESP_LOGI(TAG, "Could not fetch info on latest firmware"); - display(2, " E", "file not found"); + ota_display(2, " E", "file not found"); return -1; } else if (version_compare(latest, cfg.version) <= 0) { ESP_LOGI(TAG, "Current firmware is up to date"); - display(2, "NO", "no update found"); + ota_display(2, "NO", "no update found"); return -1; } ESP_LOGI(TAG, "New firmware version v%s available", latest.c_str()); - display(2, "OK", latest.c_str()); + ota_display(2, "OK", latest.c_str()); - display(3, "**", ""); + ota_display(3, "**", ""); if (WiFi.status() != WL_CONNECTED) return 1; String firmwarePath = bintray.getBinaryPath(latest); if (!firmwarePath.endsWith(".bin")) { ESP_LOGI(TAG, "Unsupported binary format"); - display(3, " E", "file type error"); + ota_display(3, " E", "file type error"); return -1; } @@ -158,7 +158,7 @@ int do_ota_update() { if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str()); - display(3, " E", "connection lost"); + ota_display(3, " E", "connection lost"); goto abort; } @@ -169,7 +169,7 @@ int do_ota_update() { if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s", currentHost.c_str()); - display(3, " E", "server error"); + ota_display(3, " E", "server error"); goto abort; } } @@ -185,7 +185,7 @@ int do_ota_update() { while (client.available() == 0) { if ((millis() - timeout) > (RESPONSE_TIMEOUT_MS)) { ESP_LOGI(TAG, "Client timeout"); - display(3, " E", "client timeout"); + ota_display(3, " E", "client timeout"); goto abort; } } @@ -243,12 +243,12 @@ int do_ota_update() { } // while (client.available()) } // while (redirect) - display(3, "OK", ""); // line download + ota_display(3, "OK", ""); // line download // check whether we have everything for OTA update if (!(contentLength && isValidContentType)) { ESP_LOGI(TAG, "Invalid OTA server response"); - display(4, " E", "response error"); + ota_display(4, " E", "response error"); goto retry; } @@ -262,7 +262,7 @@ int do_ota_update() { if (!Update.begin(contentLength)) { #endif ESP_LOGI(TAG, "Not enough space to start OTA update"); - display(4, " E", "disk full"); + ota_display(4, " E", "disk full"); goto abort; } @@ -271,13 +271,13 @@ int do_ota_update() { Update.onProgress(&show_progress); #endif - display(4, "**", "writing..."); + ota_display(4, "**", "writing..."); written = Update.writeStream(client); // this is a blocking call if (written == contentLength) { ESP_LOGI(TAG, "Written %u bytes successfully", written); snprintf(buf, 17, "%ukB Done!", (uint16_t)(written / 1024)); - display(4, "OK", buf); + ota_display(4, "OK", buf); } else { ESP_LOGI(TAG, "Written only %u of %u bytes, OTA update attempt cancelled", written, contentLength); @@ -288,7 +288,7 @@ int do_ota_update() { } else { ESP_LOGI(TAG, "An error occurred. Error#: %d", Update.getError()); snprintf(buf, 17, "Error#: %d", Update.getError()); - display(4, " E", buf); + ota_display(4, " E", buf); goto retry; } @@ -307,27 +307,25 @@ retry: } // do_ota_update -void display(const uint8_t row, const std::string status, - const std::string msg) { +void ota_display(const uint8_t row, const std::string status, + const std::string msg) { #ifdef HAS_DISPLAY - u8x8.setCursor(14, row); - u8x8.print((status.substr(0, 2)).c_str()); + dp_printf(112, row, 0, 0, status.substr(0, 2).c_str()); if (!msg.empty()) { - u8x8.clearLine(7); - u8x8.setCursor(0, 7); - u8x8.print(msg.substr(0, 16).c_str()); + dp_printf(0, 7, 0, 0, " "); + dp_printf(0, 7, 0, 0, msg.substr(0, 16).c_str()); } #endif } -#ifdef HAS_DISPLAY // callback function to show download progress while streaming data void show_progress(unsigned long current, unsigned long size) { +#ifdef HAS_DISPLAY char buf[17]; snprintf(buf, 17, "%-9lu (%3lu%%)", current, current * 100 / size); - display(4, "**", buf); -} + ota_display(4, "**", buf); #endif +} // helper function to convert strings into lower case bool comp(char s1, char s2) { return tolower(s1) < tolower(s2); } diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 38feccc3..79943454 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -76,7 +76,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 0 // set to 1 to use LORA timeserver 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] // settings for syncing time with timeserver applications #define TIME_SYNC_SAMPLES 1 // number of time requests for averaging From 4a686bc2673c0a62c671d6b31164821030dc9daa Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 27 Sep 2019 13:03:55 +0200 Subject: [PATCH 25/92] new oled driver (experimental) --- src/display.cpp | 19 +++++-------------- src/ota.cpp | 1 + 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index 8db7eefa..5d7127c1 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -88,13 +88,6 @@ void init_display(const char *Productname, const char *Version) { oledFill(0, 1); oledPower(cfg.screenon); // set display off if disabled - dp_printf(0, 0, 1, 0, "PAX:0"); -#if (BLECOUNTER) - dp_printf(0, 3, 0, 0, "BLTH:0"); -#endif - dp_printf(0, 4, 0, 0, "WIFI:0"); - dp_printf(0, 5, 0, 0, !cfg.rssilimit ? "RLIM:off " : "RLIM:%d", - cfg.rssilimit); I2C_MUTEX_UNLOCK(); // release i2c bus access } // mutex @@ -201,16 +194,14 @@ void draw_page(time_t t, uint8_t page) { TimePulseTick = false; // display inverse timeState if clock controller is enabled #if (defined HAS_DCF77) || (defined HAS_IF482) - dp_printf(0, 6, FONT_SMALL, 0, "%02d:%02d:%02d", hour(t), minute(t), - second(t)); - dp_printf(56, 6, FONT_SMALL, 1, "%c", timeState); + dp_printf(0, 6, 0, 0, "%02d:%02d:%02d", hour(t), minute(t), second(t)); + dp_printf(56, 6, 0, 1, "%c", timeState); #else - dp_printf(0, 6, FONT_SMALL, 0, "%02d:%02d:%02d%c", hour(t), minute(t), - second(t), timeState); + dp_printf(0, 6, 0, 0, "%02d:%02d:%02d%c", hour(t), minute(t), second(t), + timeState); #endif // HAS_DCF77 || HAS_IF482 if (timeSource != _unsynced) - dp_printf(72, 6, FONT_SMALL, 0, " %2d.%3s%4s", day(t), - printmonth[month(t)], year(t)); + dp_printf(72, 6, 0, 0, " %2d.%3s", day(t), printmonth[month(t)]); #endif // TIME_SYNC_INTERVAL diff --git a/src/ota.cpp b/src/ota.cpp index e05b6f8f..91d28e11 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -64,6 +64,7 @@ void start_ota_update() { dp_printf(0, 3, 0, 0, "Fetching .."); dp_printf(0, 4, 0, 0, "Downloading .."); dp_printf(0, 5, 0, 0, "Rebooting .."); +#endif ESP_LOGI(TAG, "Starting Wifi OTA update"); ota_display(1, "**", WIFI_SSID); From c30ee996be58f29142044d8a5601599058a66075 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 27 Sep 2019 17:37:16 +0200 Subject: [PATCH 26/92] new display mask --- src/display.cpp | 137 ++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 68 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index 5d7127c1..c2fa81c1 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -4,23 +4,31 @@ Display-Mask (128 x 64 pixel): - | 111111 - |0123456789012345 ------------------- -0|PAX:aabbccddee -1|PAX:aabbccddee -2|B:a.bcV Sats:ab -3|BLTH:abcde SFab -4|WIFI:abcde ch:ab -5|RLIM:abcd abcdKB -6|20:27:00* 27.Feb -7|yyyyyyyyyyyyyyab + | | | + | 11111111112 + |012345678901234567890 Font +----------------------- --------- +0|PAX:aabbccdd STRETCHED +1|PAX:aabbccdd STRETCHED +2| +3|B:a.bcV Sats:ab ch:ab SMALL +4|WIFI:abcde BLTH:abcde SMALL +5|RLIM:abcd Mem:abcdKB SMALL +6|27.Feb 2019 20:27:00* SMALL +7|yyyyyyyyyyyyyyyy SFab SMALL -line 6: * = char {L|G|R|?} indicates time source, - inverse = clock controller is active, - pulsed = pps input signal is active +* = 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 +y = LMIC event message; ab = payload queue length + +FONTS in ss_oled.cpp: + +FONT_SMALL: 6px = 21 chars / line +FONT_NORMAL: 8px = 16 chars / line +FONT_STRETCHED: 8 chars / line +FONT_LARGE: 8 chars / line */ @@ -134,7 +142,7 @@ void draw_page(time_t t, uint8_t page) { static bool wasnofix = true; #endif - // update counter (lines 0-1) + // line 1/2: pax counter dp_printf(0, 0, FONT_STRETCHED, 0, "PAX:%-4d", (int)macs.size()); // display number of unique macs total Wifi + BLE @@ -147,82 +155,75 @@ void draw_page(time_t t, uint8_t page) { case 0: -// update Battery status (line 2) -#if (defined BAT_MEASURE_ADC || defined HAS_PMU) - if (batt_voltage == 0xffff) - dp_printf(0, 2, 0, 0, "%s", "B:USB "); - else - dp_printf(0, 2, 0, 0, "B:%.2fV", batt_voltage / 1000.0); -#endif - -// update GPS status (line 2) -#if (HAS_GPS) - if (gps.location.age() < 1500) // if no fix then display Sats value inverse - dp_printf(72, 2, 0, 0, "Sats:%.2d", gps.satellites.value()); - else - dp_printf(72, 2, 0, 1, "Sats:%.2d", gps.satellites.value()); -#endif - - // update bluetooth counter + LoRa SF (line 3) + // line 3: wifi + bluetooth counters + dp_printf(0, 3, FONT_SMALL, 0, "WIFI:%-5d", macs_wifi); #if (BLECOUNTER) if (cfg.blescan) - dp_printf(0, 3, 0, 0, "BLTH:%-5d", macs_ble); + dp_printf(66, 3, FONT_SMALL, 0, "BLTH:%-5d", macs_ble); else - dp_printf(0, 3, 0, 0, "%s", "BLTH:off"); + dp_printf(66, 3, FONT_SMALL, 0, "%s", "BLTH:off"); #endif -#if (HAS_LORA) - if (cfg.adrmode) - dp_printf(96, 3, 0, 0, "%-4s", getSfName(updr2rps(LMIC.datarate))); - else // if ADR=off then display SF value inverse - dp_printf(96, 3, 0, 1, "%-4s", getSfName(updr2rps(LMIC.datarate))); -#endif // HAS_LORA +// line 4: Battery + GPS status + Wifi channel +#if (defined BAT_MEASURE_ADC || defined HAS_PMU) + if (batt_voltage == 0xffff) + dp_printf(0, 4, FONT_SMALL, 0, "%s", "B:USB "); + else + dp_printf(0, 4, FONT_SMALL, 0, "B:%.2fV", batt_voltage / 1000.0); +#endif +#if (HAS_GPS) + if (gps.location.age() < 1500) // if no fix then display Sats value inverse + dp_printf(48, 4, FONT_SMALL, 0, "Sats:%.2d", gps.satellites.value()); + else + dp_printf(48, 4, FONT_SMALL, 1, "Sats:%.2d", gps.satellites.value()); +#endif + dp_printf(96, 4, FONT_SMALL, 0, "ch:%02d", channel); - // line 4: update wifi counter + channel display - dp_printf(0, 4, 0, 0, "WIFI:%-5d", macs_wifi); - dp_printf(88, 4, 0, 0, "ch:%02d", channel); - - // line 5: update RSSI limiter status & free memory display - dp_printf(0, 5, 0, 0, !cfg.rssilimit ? "RLIM:off " : "RLIM:%-4d", + // line 5: RSSI limiter + free memory + dp_printf(0, 5, FONT_SMALL, 0, !cfg.rssilimit ? "RLIM:off " : "RLIM:%-4d", cfg.rssilimit); - dp_printf(80, 5, 0, 0, "%4dKB", getFreeRAM() / 1024); + dp_printf(66, 5, FONT_SMALL, 0, "Mem:%4dKB", getFreeRAM() / 1024); - // line 6: update time-of-day or LoRa status display + // line 6: time + date #if (TIME_SYNC_INTERVAL) - // we want a systime display instead LoRa status timeState = TimePulseTick ? ' ' : timeSetSymbols[timeSource]; TimePulseTick = false; + + dp_printf(0, 6, FONT_SMALL, 0, "%02d.%3s %4d", day(t), printmonth[month(t)], + year(t)); + dp_printf(72, 6, FONT_SMALL, 0, "%02d:%02d:%02d", hour(t), minute(t), + second(t)); + // display inverse timeState if clock controller is enabled #if (defined HAS_DCF77) || (defined HAS_IF482) - dp_printf(0, 6, 0, 0, "%02d:%02d:%02d", hour(t), minute(t), second(t)); - dp_printf(56, 6, 0, 1, "%c", timeState); + dp_printf(120, 6, FONT_SMALL, 1, "%c", timeState); #else - dp_printf(0, 6, 0, 0, "%02d:%02d:%02d%c", hour(t), minute(t), second(t), - timeState); -#endif // HAS_DCF77 || HAS_IF482 - if (timeSource != _unsynced) - dp_printf(72, 6, 0, 0, " %2d.%3s", day(t), printmonth[month(t)]); + dp_printf(120, 6, FONT_SMALL, 0, "%c", timeState); +#endif #endif // TIME_SYNC_INTERVAL + // line 7: LORA network status #if (HAS_LORA) - // line 7: update LMiC event display - dp_printf(0, 7, FONT_SMALL, 0, "%-14s", lmic_event_msg); - - // update LoRa send queue display + // LMiC event display, display inverse if sendqueue not empty msgWaiting = uxQueueMessagesWaiting(LoraSendQueue); - if (msgWaiting) { - sprintf(buff, "%2d", msgWaiting); - dp_printf(112, 7, FONT_SMALL, 0, "%-2s", - msgWaiting == SEND_QUEUE_SIZE ? "<>" : buff); - } else - dp_printf(112, 7, FONT_SMALL, 0, " "); + if (msgWaiting) + dp_printf(0, 7, FONT_SMALL, 1, "%-17s", lmic_event_msg); + else + dp_printf(0, 7, FONT_SMALL, 0, "%-17s", lmic_event_msg); + // LORA datarate, display inverse if ADR disabled + if (cfg.adrmode) + dp_printf(108, 7, FONT_SMALL, 0, "%-4s", + getSfName(updr2rps(LMIC.datarate))); + else + dp_printf(108, 7, FONT_SMALL, 1, "%-4s", + getSfName(updr2rps(LMIC.datarate))); #endif // HAS_LORA break; // page0 case 1: - dp_printf(0, 4, FONT_STRETCHED, 0, "%02d:%02d:%02d", hour(t), minute(t), + dp_printf(0, 4, FONT_LARGE, 0, "%02d:%02d:%02d", hour(t), minute(t), second(t)); break; // page1 From ad6a7b3adeb79dcfc665732e791a52143ab58692 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 27 Sep 2019 17:47:39 +0200 Subject: [PATCH 27/92] removed productname --- src/paxcounter.conf | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 79943454..334a3431 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -6,8 +6,6 @@ // // Note: After editing, before "build", use "clean" button in PlatformIO! -#define PRODUCTNAME "PAXCNT" - // Verbose enables serial output #define VERBOSE 1 // set to 0 to silence the device, for mute use build option @@ -18,7 +16,7 @@ // Set this to include BLE counting and vendor filter functions, or to switch off WIFI counting #define VENDORFILTER 1 // set to 0 if you want to count things, not people -#define BLECOUNTER 0 // set it to 1 if you want to use BLE count, at expense of power & memory +#define BLECOUNTER 1 // set it to 1 if you want to use BLE count, at expense of power & memory #define WIFICOUNTER 1 // set it to 0 if you want to switch off WIFI count // BLE scan parameters From 8cb5bbab54b96df20e13bb4203d2a625b97c90f6 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 27 Sep 2019 17:57:19 +0200 Subject: [PATCH 28/92] removed productname --- include/display.h | 2 +- src/display.cpp | 2 +- src/main.cpp | 4 ++-- src/paxcounter.conf | 6 ++---- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/display.h b/include/display.h index 90ea3f38..0431bd8b 100644 --- a/include/display.h +++ b/include/display.h @@ -5,7 +5,7 @@ extern uint8_t DisplayIsOn; -void init_display(const char *Productname, const char *Version); +void init_display(void); void refreshTheDisplay(bool nextPage = false); void draw_page(time_t t, uint8_t page); void dp_printf(int x, int y, int font, int inv, const char *format, ...); diff --git a/src/display.cpp b/src/display.cpp index c2fa81c1..4e35d615 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -46,7 +46,7 @@ const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", uint8_t DisplayIsOn = 0; -void init_display(const char *Productname, const char *Version) { +void init_display(void) { // block i2c bus access if (!I2C_MUTEX_LOCK()) diff --git a/src/main.cpp b/src/main.cpp index 91741688..908313e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -129,7 +129,7 @@ void setup() { esp_log_level_set("*", ESP_LOG_NONE); #endif - ESP_LOGI(TAG, "Starting %s v%s", PRODUCTNAME, PROGVERSION); + ESP_LOGI(TAG, "Starting Software v%s", PROGVERSION); // print chip information on startup if in verbose mode #if (VERBOSE) @@ -200,7 +200,7 @@ void setup() { #ifdef HAS_DISPLAY strcat_P(features, " OLED"); DisplayIsOn = cfg.screenon; - init_display(PRODUCTNAME, PROGVERSION); // note: blocking call + init_display(); // note: blocking call #endif #ifdef BOARD_HAS_PSRAM diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 79943454..2fabde60 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -6,8 +6,6 @@ // // Note: After editing, before "build", use "clean" button in PlatformIO! -#define PRODUCTNAME "PAXCNT" - // Verbose enables serial output #define VERBOSE 1 // set to 0 to silence the device, for mute use build option @@ -18,7 +16,7 @@ // Set this to include BLE counting and vendor filter functions, or to switch off WIFI counting #define VENDORFILTER 1 // set to 0 if you want to count things, not people -#define BLECOUNTER 0 // set it to 1 if you want to use BLE count, at expense of power & memory +#define BLECOUNTER 1 // set it to 1 if you want to use BLE count, at expense of power & memory #define WIFICOUNTER 1 // set it to 0 if you want to switch off WIFI count // BLE scan parameters @@ -76,7 +74,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 From c6c455b922ec92dd328e42921ed3547b1276430a Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 29 Sep 2019 16:46:48 +0200 Subject: [PATCH 29/92] QR display of DEVEUI (experimental) --- include/display.h | 5 +++- src/display.cpp | 58 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/include/display.h b/include/display.h index 0431bd8b..fe1fd995 100644 --- a/include/display.h +++ b/include/display.h @@ -2,12 +2,15 @@ #define _DISPLAY_H #include "cyclic.h" +#include "qrcode.h" extern uint8_t DisplayIsOn; -void init_display(void); void refreshTheDisplay(bool nextPage = false); +void init_display(void); void draw_page(time_t t, uint8_t page); void dp_printf(int x, int y, int font, int inv, const char *format, ...); +void dp_printqr(int offset_x, int offset_y, const char *Message); +void oledfillRect(int x, int y, int width, int height, int bRender); #endif \ No newline at end of file diff --git a/src/display.cpp b/src/display.cpp index 4e35d615..ed2f26dd 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -23,12 +23,9 @@ Display-Mask (128 x 64 pixel): y = LMIC event message; ab = payload queue length -FONTS in ss_oled.cpp: - -FONT_SMALL: 6px = 21 chars / line -FONT_NORMAL: 8px = 16 chars / line -FONT_STRETCHED: 8 chars / line -FONT_LARGE: 8 chars / line +FONT_SMALL: 6x8px = 21 chars / line +FONT_NORMAL: 8x8px = 16 chars / line +FONT_STRETCHED: 16x32px = 8 chars / line */ @@ -37,15 +34,26 @@ FONT_LARGE: 8 chars / line #include #include // needed for reading ESP32 chip attributes +// local Tag for logging +static const char TAG[] = __FILE__; + +// settings for oled display library #define DISPLAY_PAGES (4) // number of display pages #define USE_BACKBUFFER // for display library +// settings for qr code generator +#define ELEMENT_SIZE 3 +#define QR_VERSION 1 +#define LOCK_VERSION 1 + // helper arry for converting month values to text const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; uint8_t DisplayIsOn = 0; +QRCode qrcode; + void init_display(void) { // block i2c bus access @@ -78,23 +86,29 @@ void init_display(void) { dp_printf(0, 3, 0, 0, "%dMB %s Flash", spi_flash_get_chip_size() / (1024 * 1024), (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext."); + dp_printf(0, 4, 0, 0, "Software v%s", PROGVERSION); #endif // VERBOSE #if (HAS_LORA) - uint8_t buf[34]; + // generate and show DEVEUI + uint8_t buf[8]; const uint8_t *p; os_getDevEui((u1_t *)buf); - dp_printf(0, 5, 0, 0, "DEVEUI:"); + dp_printf(0, 6, 0, 0, "DEVEUI:"); for (uint8_t i = 0; i < 8; i++) { p = buf + 7 - i; - dp_printf(i * 16, 6, 0, 0, "%02X", *p); + dp_printf(i * 16, 7, 0, 0, "%02X", *p); } -#endif // HAS_LORA - - dp_printf(0, 4, 0, 0, "Software v%s", PROGVERSION); delay(3000); + oledFill(0x00, 1); - oledFill(0, 1); + // print DEVEUI as QR code + const char *eui = reinterpret_cast(buf); + dp_printqr(0, 0, eui); // to come: we need inverted display for QR code + +#endif // HAS_LOR + delay(3000); + oledFill(0x00, 1); oledPower(cfg.screenon); // set display off if disabled I2C_MUTEX_UNLOCK(); // release i2c bus access @@ -281,8 +295,7 @@ void draw_page(time_t t, uint8_t page) { } // draw_page -// display print helper function - +// display print helper functions void dp_printf(int x, int y, int font, int inv, const char *format, ...) { char loc_buf[64]; char *temp = loc_buf; @@ -311,4 +324,19 @@ void dp_printf(int x, int y, int font, int inv, const char *format, ...) { } } +void dp_printqr(int offset_x, int offset_y, const char *Message) { + uint8_t qrcodeData[qrcode_getBufferSize(1)]; + qrcode_initText(&qrcode, qrcodeData, QR_VERSION, ECC_HIGH, Message); + for (int y = 0; y < qrcode.size; y++) + for (int x = 0; x < qrcode.size; x++) + if (qrcode_getModule(&qrcode, x, y)) // BLACK + oledfillRect(x * ELEMENT_SIZE + offset_x, y * ELEMENT_SIZE + offset_y, + ELEMENT_SIZE, ELEMENT_SIZE, true); +} + +void oledfillRect(int x, int y, int width, int height, int bRender) { + for (int xi = x; xi < x + width; xi++) + oledDrawLine(xi, y, xi, y + height - 1, bRender); +} + #endif // HAS_DISPLAY \ No newline at end of file From 8b42cd3e3d8b437cfaaf71aab362094e4fbb1560 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 29 Sep 2019 17:38:16 +0200 Subject: [PATCH 30/92] QR display (experimental) --- src/display.cpp | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index ed2f26dd..ec5ee33f 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -42,8 +42,8 @@ static const char TAG[] = __FILE__; #define USE_BACKBUFFER // for display library // settings for qr code generator -#define ELEMENT_SIZE 3 -#define QR_VERSION 1 +#define QR_VERSION 3 // 29 x 29px +#define QR_SCALEFACTOR 2 // 29 -> 58x < 64px #define LOCK_VERSION 1 // helper arry for converting month values to text @@ -94,21 +94,36 @@ void init_display(void) { uint8_t buf[8]; const uint8_t *p; os_getDevEui((u1_t *)buf); - dp_printf(0, 6, 0, 0, "DEVEUI:"); + dp_printf(0, 6, 0, 1, "LORAWAN DEVEUI: "); for (uint8_t i = 0; i < 8; i++) { p = buf + 7 - i; - dp_printf(i * 16, 7, 0, 0, "%02X", *p); + dp_printf(i * 16, 7, 0, 1, "%02X", *p); } delay(3000); oledFill(0x00, 1); +// we need to invert display to show QR code +#ifndef DISPLAY_FLIP + oledInit(OLED_128x64, ANGLE_0, true, -1, -1, 400000L); +#else + oledInit(OLED_128x64, ANGLE_FLIPY, true, -1, -1, 400000L); +#endif + // print DEVEUI as QR code const char *eui = reinterpret_cast(buf); - dp_printqr(0, 0, eui); // to come: we need inverted display for QR code - -#endif // HAS_LOR - delay(3000); + dp_printqr(3, 3, eui); + delay(300000); oledFill(0x00, 1); + + // display back to normal +#ifndef DISPLAY_FLIP + oledInit(OLED_128x64, ANGLE_0, true, -1, -1, 400000L); +#else + oledInit(OLED_128x64, ANGLE_FLIPY, true, -1, -1, 400000L); +#endif + +#endif // HAS_LORA + oledPower(cfg.screenon); // set display off if disabled I2C_MUTEX_UNLOCK(); // release i2c bus access @@ -325,13 +340,15 @@ void dp_printf(int x, int y, int font, int inv, const char *format, ...) { } void dp_printqr(int offset_x, int offset_y, const char *Message) { - uint8_t qrcodeData[qrcode_getBufferSize(1)]; + uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; qrcode_initText(&qrcode, qrcodeData, QR_VERSION, ECC_HIGH, Message); for (int y = 0; y < qrcode.size; y++) for (int x = 0; x < qrcode.size; x++) - if (qrcode_getModule(&qrcode, x, y)) // BLACK - oledfillRect(x * ELEMENT_SIZE + offset_x, y * ELEMENT_SIZE + offset_y, - ELEMENT_SIZE, ELEMENT_SIZE, true); + if (qrcode_getModule(&qrcode, x, y)) // "black" + oledfillRect(x * QR_SCALEFACTOR + offset_x, + y * QR_SCALEFACTOR + offset_y, QR_SCALEFACTOR, + QR_SCALEFACTOR, true); + oledfillRect(64, 0, 64, 64, true); // clear white space beneath qr code } void oledfillRect(int x, int y, int width, int height, int bRender) { From 899c8315b4daa4363842338e00918a1950bcd1d9 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 29 Sep 2019 23:16:36 +0200 Subject: [PATCH 31/92] DEVEUI QR code display --- src/display.cpp | 66 +++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index ec5ee33f..1ab38f99 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -86,42 +86,37 @@ void init_display(void) { dp_printf(0, 3, 0, 0, "%dMB %s Flash", spi_flash_get_chip_size() / (1024 * 1024), (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext."); - dp_printf(0, 4, 0, 0, "Software v%s", PROGVERSION); + dp_printf(0, 5, 0, 0, "Software v%s", PROGVERSION); + + // give user some time to read or take picture + delay(2000); + oledFill(0x00, 1); #endif // VERBOSE #if (HAS_LORA) - // generate and show DEVEUI + // generate DEVEUI as QR code and text uint8_t buf[8]; const uint8_t *p; os_getDevEui((u1_t *)buf); - dp_printf(0, 6, 0, 1, "LORAWAN DEVEUI: "); - for (uint8_t i = 0; i < 8; i++) { - p = buf + 7 - i; - dp_printf(i * 16, 7, 0, 1, "%02X", *p); - } + + // display DEVEUI as QR code on the left + char converted[17]; + sprintf(converted, "%016llX", *((uint64_t *)&buf)); + oledSetContrast(20); + dp_printqr(3, 3, converted); + + // display DEVEUI as plain text on the right + dp_printf(72, 0, FONT_NORMAL, 0, "LORAWAN"); + dp_printf(72, 1, FONT_NORMAL, 0, "DEVEUI:"); + dp_printf(80, 3, FONT_NORMAL, 0, "%4.4s", converted); + dp_printf(80, 4, FONT_NORMAL, 0, "%4.4s", converted + 4); + dp_printf(80, 5, FONT_NORMAL, 0, "%4.4s", converted + 8); + dp_printf(80, 6, FONT_NORMAL, 0, "%4.4s", converted + 12); + + // give user some time to read or take picture delay(3000); + oledSetContrast(255); oledFill(0x00, 1); - -// we need to invert display to show QR code -#ifndef DISPLAY_FLIP - oledInit(OLED_128x64, ANGLE_0, true, -1, -1, 400000L); -#else - oledInit(OLED_128x64, ANGLE_FLIPY, true, -1, -1, 400000L); -#endif - - // print DEVEUI as QR code - const char *eui = reinterpret_cast(buf); - dp_printqr(3, 3, eui); - delay(300000); - oledFill(0x00, 1); - - // display back to normal -#ifndef DISPLAY_FLIP - oledInit(OLED_128x64, ANGLE_0, true, -1, -1, 400000L); -#else - oledInit(OLED_128x64, ANGLE_FLIPY, true, -1, -1, 400000L); -#endif - #endif // HAS_LORA oledPower(cfg.screenon); // set display off if disabled @@ -342,13 +337,24 @@ void dp_printf(int x, int y, int font, int inv, const char *format, ...) { void dp_printqr(int offset_x, int offset_y, const char *Message) { uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; qrcode_initText(&qrcode, qrcodeData, QR_VERSION, ECC_HIGH, Message); + + // draw QR code for (int y = 0; y < qrcode.size; y++) for (int x = 0; x < qrcode.size; x++) - if (qrcode_getModule(&qrcode, x, y)) // "black" + if (!qrcode_getModule(&qrcode, x, y)) // "black" oledfillRect(x * QR_SCALEFACTOR + offset_x, y * QR_SCALEFACTOR + offset_y, QR_SCALEFACTOR, QR_SCALEFACTOR, true); - oledfillRect(64, 0, 64, 64, true); // clear white space beneath qr code + // draw horizontal frame lines + oledfillRect(0, 0, qrcode.size * QR_SCALEFACTOR + 2 * offset_x, offset_y, + true); + oledfillRect(0, qrcode.size * QR_SCALEFACTOR + offset_y, + qrcode.size * QR_SCALEFACTOR + 2 * offset_x, offset_y, true); + // draw vertical frame lines + oledfillRect(0, 0, offset_x, qrcode.size * QR_SCALEFACTOR + 2 * offset_y, + true); + oledfillRect(qrcode.size * QR_SCALEFACTOR + offset_x, 0, offset_x, + qrcode.size * QR_SCALEFACTOR + 2 * offset_y, true); } void oledfillRect(int x, int y, int width, int height, int bRender) { From 55874f8b43ec122841d004972eb0890aec6d6b0f Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 29 Sep 2019 23:24:13 +0200 Subject: [PATCH 32/92] startup screen --- src/display.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index 1ab38f99..ead88d30 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -78,15 +78,17 @@ void init_display(void) { #if (VERBOSE) esp_chip_info_t chip_info; esp_chip_info(&chip_info); - dp_printf(0, 0, 0, 0, "ESP32 %d cores", chip_info.cores); - dp_printf(0, 2, 0, 0, "Chip Rev.%d", chip_info.revision); - dp_printf(0, 1, 0, 0, "WiFi%s%s", + dp_printf(0, 0, 0, 0, "** PAXCOUNTER **"); + dp_printf(0, 1, 0, 0, "Software v%s", PROGVERSION); + dp_printf(0, 3, 0, 0, "ESP32 %d cores", chip_info.cores); + dp_printf(0, 4, 0, 0, "Chip Rev.%d", chip_info.revision); + dp_printf(0, 5, 0, 0, "WiFi%s%s", (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); - dp_printf(0, 3, 0, 0, "%dMB %s Flash", + dp_printf(0, 6, 0, 0, "%dMB %s Flash", spi_flash_get_chip_size() / (1024 * 1024), (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext."); - dp_printf(0, 5, 0, 0, "Software v%s", PROGVERSION); + // give user some time to read or take picture delay(2000); From 58ed680a92f6b38365ec2d70b6ce931dd114428e Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 30 Sep 2019 11:45:35 +0200 Subject: [PATCH 33/92] ota.cpp: WIFI response timeout added --- src/ota.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ota.cpp b/src/ota.cpp index 91d28e11..6959792b 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -52,9 +52,9 @@ void start_ota_update() { // init display #ifndef DISPLAY_FLIP - int rc = oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 100000L); + oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 100000L); #else - int rc = oledInit(OLED_128x64, ANGLE_FLIPY, false, -1, -1, 100000L); + oledInit(OLED_128x64, ANGLE_FLIPY, false, -1, -1, 100000L); #endif oledFill(0, 1); @@ -157,7 +157,7 @@ int do_ota_update() { client.setCACert(bintray.getCertificate(currentHost)); client.setTimeout(RESPONSE_TIMEOUT_MS); - if (!client.connect(currentHost.c_str(), port)) { + if (!client.connect(currentHost.c_str(), port, RESPONSE_TIMEOUT_MS)) { ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str()); ota_display(3, " E", "connection lost"); goto abort; @@ -167,7 +167,7 @@ int do_ota_update() { if (currentHost != prevHost) { client.stop(); client.setCACert(bintray.getCertificate(currentHost)); - if (!client.connect(currentHost.c_str(), port)) { + if (!client.connect(currentHost.c_str(), port, RESPONSE_TIMEOUT_MS)) { ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s", currentHost.c_str()); ota_display(3, " E", "server error"); From c93b0867a9fd3153ab6be1026f2f2c39d8e51a5c Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 30 Sep 2019 12:35:03 +0200 Subject: [PATCH 34/92] AXP192 low level I2C mutexing --- include/power.h | 2 + src/power.cpp | 212 +++++++++++++++++++++++++++--------------------- 2 files changed, 121 insertions(+), 93 deletions(-) diff --git a/include/power.h b/include/power.h index 1ef571e1..1af87f09 100644 --- a/include/power.h +++ b/include/power.h @@ -19,6 +19,8 @@ void power_event_IRQ(void); void AXP192_power(bool on); void AXP192_init(void); void AXP192_showstatus(void); +uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len); +uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len); #endif // HAS_PMU #endif \ No newline at end of file diff --git a/src/power.cpp b/src/power.cpp index 6b7f1f5e..7d29d5b4 100644 --- a/src/power.cpp +++ b/src/power.cpp @@ -11,48 +11,41 @@ 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(); - 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.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."); - 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; + } - // 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(); + } - // shutdown power - if (pmu.isPEKLongtPressIRQ()) { - AXP192_power(false); // switch off Lora, GPS, display - pmu.shutdown(); - } - - pmu.clearIRQ(); - I2C_MUTEX_UNLOCK(); - } // mutex + pmu.clearIRQ(); // refresh stored voltage value read_voltage(); @@ -75,70 +68,103 @@ void AXP192_power(bool on) { 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"); + if (pmu.isBatteryConnect()) + if (pmu.isChargeing()) + ESP_LOGI(TAG, "Battery charging, %.2fV @ %.0fmAh", + pmu.getBattVoltage() / 1000, pmu.getBattChargeCurrent()); else - ESP_LOGI(TAG, "No Battery"); + 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 + if (pmu.isVBUSPlug()) + ESP_LOGI(TAG, "USB powered, %.0fmW", + pmu.getVbusVoltage() / 1000 * pmu.getVbusCurrent()); + else + ESP_LOGI(TAG, "USB not present"); } void AXP192_init(void) { - // block i2c bus access - if (I2C_MUTEX_LOCK()) { + if (pmu.begin(i2c_readBytes, i2c_writeBytes, AXP192_PRIMARY_ADDRESS) == AXP_FAIL) + ESP_LOGI(TAG, "AXP192 PMU initialization failed"); + else { - 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 - // 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 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); - // 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(); + 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"); + ESP_LOGI(TAG, "AXP192 PMU initialized"); + } } + +// helper functions for mutexing i2c access +uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) { + if (I2C_MUTEX_LOCK()) { + + uint8_t ret = 0; + Wire.beginTransmission(addr); + Wire.write(reg); + Wire.endTransmission(false); + uint8_t cnt = Wire.requestFrom(addr, (uint8_t)len, (uint8_t)1); + if (!cnt) { + ret = 0xFF; + } + uint16_t index = 0; + while (Wire.available()) { + if (index > len) + return 0xFF; + data[index++] = Wire.read(); + } + + I2C_MUTEX_UNLOCK(); // release i2c bus access + return ret; + } else { + ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0); + return 0xFF; + } +} + +uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) { + if (I2C_MUTEX_LOCK()) { + + uint8_t ret = 0; + Wire.beginTransmission(addr); + Wire.write(reg); + for (uint16_t i = 0; i < len; i++) { + Wire.write(data[i]); + } + ret = Wire.endTransmission(); + + I2C_MUTEX_UNLOCK(); // release i2c bus access + return ret ? 0xFF : ret; + //return ret ? ret : 0xFF; + } else { + ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0); + return 0xFF; + } +} + #endif // HAS_PMU #ifdef BAT_MEASURE_ADC @@ -196,12 +222,12 @@ 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(); - } + // 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 From 8cbac9c79f18dbe57eac751522b0ea136ebdc3d4 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 30 Sep 2019 12:36:13 +0200 Subject: [PATCH 35/92] speedup display (use pagemode & i2c 400khz) --- src/display.cpp | 41 +++++++++++++++++++++-------------------- src/main.cpp | 4 ++-- src/ota.cpp | 4 ++-- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index ead88d30..6a3b5e47 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -44,7 +44,6 @@ static const char TAG[] = __FILE__; // settings for qr code generator #define QR_VERSION 3 // 29 x 29px #define QR_SCALEFACTOR 2 // 29 -> 58x < 64px -#define LOCK_VERSION 1 // helper arry for converting month values to text const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -69,6 +68,7 @@ void init_display(void) { #endif // clear display + oledSetContrast(DISPLAYCONTRAST); oledFill(0, 1); // show startup screen @@ -88,9 +88,9 @@ void init_display(void) { dp_printf(0, 6, 0, 0, "%dMB %s Flash", spi_flash_get_chip_size() / (1024 * 1024), (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext."); - // give user some time to read or take picture + oledDumpBuffer(NULL); delay(2000); oledFill(0x00, 1); #endif // VERBOSE @@ -98,26 +98,26 @@ void init_display(void) { #if (HAS_LORA) // generate DEVEUI as QR code and text uint8_t buf[8]; - const uint8_t *p; + char deveui[17]; os_getDevEui((u1_t *)buf); + sprintf(deveui, "%016llX", *((uint64_t *)&buf)); // display DEVEUI as QR code on the left - char converted[17]; - sprintf(converted, "%016llX", *((uint64_t *)&buf)); - oledSetContrast(20); - dp_printqr(3, 3, converted); + oledSetContrast(30); + dp_printqr(3, 3, deveui); // display DEVEUI as plain text on the right dp_printf(72, 0, FONT_NORMAL, 0, "LORAWAN"); dp_printf(72, 1, FONT_NORMAL, 0, "DEVEUI:"); - dp_printf(80, 3, FONT_NORMAL, 0, "%4.4s", converted); - dp_printf(80, 4, FONT_NORMAL, 0, "%4.4s", converted + 4); - dp_printf(80, 5, FONT_NORMAL, 0, "%4.4s", converted + 8); - dp_printf(80, 6, FONT_NORMAL, 0, "%4.4s", converted + 12); + dp_printf(80, 3, FONT_NORMAL, 0, "%4.4s", deveui); + dp_printf(80, 4, FONT_NORMAL, 0, "%4.4s", deveui + 4); + dp_printf(80, 5, FONT_NORMAL, 0, "%4.4s", deveui + 8); + dp_printf(80, 6, FONT_NORMAL, 0, "%4.4s", deveui + 12); // give user some time to read or take picture - delay(3000); - oledSetContrast(255); + oledDumpBuffer(NULL); + delay(8000); + oledSetContrast(DISPLAYCONTRAST); oledFill(0x00, 1); #endif // HAS_LORA @@ -154,6 +154,7 @@ void refreshTheDisplay(bool nextPage) { } draw_page(t, DisplayPage); + oledDumpBuffer(NULL); I2C_MUTEX_UNLOCK(); // release i2c bus access @@ -162,7 +163,7 @@ void refreshTheDisplay(bool nextPage) { void draw_page(time_t t, uint8_t page) { - char timeState, buff[16]; + char timeState; uint8_t msgWaiting; #if (HAS_GPS) static bool wasnofix = true; @@ -330,7 +331,7 @@ void dp_printf(int x, int y, int font, int inv, const char *format, ...) { len = vsnprintf(temp, len + 1, format, arg); } va_end(arg); - oledWriteString(0, x, y, temp, font, inv, 1); + oledWriteString(0, x, y, temp, font, inv, false); if (temp != loc_buf) { free(temp); } @@ -346,17 +347,17 @@ void dp_printqr(int offset_x, int offset_y, const char *Message) { if (!qrcode_getModule(&qrcode, x, y)) // "black" oledfillRect(x * QR_SCALEFACTOR + offset_x, y * QR_SCALEFACTOR + offset_y, QR_SCALEFACTOR, - QR_SCALEFACTOR, true); + QR_SCALEFACTOR, false); // draw horizontal frame lines oledfillRect(0, 0, qrcode.size * QR_SCALEFACTOR + 2 * offset_x, offset_y, - true); + false); oledfillRect(0, qrcode.size * QR_SCALEFACTOR + offset_y, - qrcode.size * QR_SCALEFACTOR + 2 * offset_x, offset_y, true); + qrcode.size * QR_SCALEFACTOR + 2 * offset_x, offset_y, false); // draw vertical frame lines oledfillRect(0, 0, offset_x, qrcode.size * QR_SCALEFACTOR + 2 * offset_y, - true); + false); oledfillRect(qrcode.size * QR_SCALEFACTOR + offset_x, 0, offset_x, - qrcode.size * QR_SCALEFACTOR + 2 * offset_y, true); + qrcode.size * QR_SCALEFACTOR + 2 * offset_y, false); } void oledfillRect(int x, int y, int width, int height, int bRender) { diff --git a/src/main.cpp b/src/main.cpp index 908313e8..a23b2b52 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -172,9 +172,9 @@ void setup() { // open i2c bus #ifdef HAS_DISPLAY - Wire.begin(MY_OLED_SDA, MY_OLED_SCL, 100000); + Wire.begin(MY_OLED_SDA, MY_OLED_SCL, 400000); #else - Wire.begin(SDA, SCL, 100000); + Wire.begin(SDA, SCL, 400000); #endif // setup power on boards with power management logic diff --git a/src/ota.cpp b/src/ota.cpp index 6959792b..416a4d93 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -52,9 +52,9 @@ void start_ota_update() { // init display #ifndef DISPLAY_FLIP - oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 100000L); + oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 400000L); #else - oledInit(OLED_128x64, ANGLE_FLIPY, false, -1, -1, 100000L); + oledInit(OLED_128x64, ANGLE_FLIPY, false, -1, -1, 400000L); #endif oledFill(0, 1); From d58e8a11db9ef25f52d1553cddcf01c03e31f86a Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 30 Sep 2019 15:05:30 +0200 Subject: [PATCH 36/92] paxcounter.conf: add DISPLAYCONTRAST --- src/paxcounter.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 2fabde60..21340850 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -55,6 +55,7 @@ // Hardware settings #define RGBLUMINOSITY 30 // RGB LED luminosity [default = 30%] #define DISPLAYREFRESH_MS 40 // OLED refresh cycle in ms [default = 40] -> 1000/40 = 25 frames per second +#define DISPLAYCONTRAST 80 // 0 .. 255, OLED display contrast [default = 80] #define HOMECYCLE 30 // house keeping cycle in seconds [default = 30 secs] // Settings for BME680 environmental sensor @@ -74,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 0 // 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 From 449d681c7b33ab5c3a4592c8520afa4d7989fc42 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 30 Sep 2019 19:44:49 +0200 Subject: [PATCH 37/92] LEDmatrixdisplay.cpp/.h rename scrollfunction --- include/ledmatrixdisplay.h | 2 +- src/ledmatrixdisplay.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/ledmatrixdisplay.h b/include/ledmatrixdisplay.h index b7ec5a3b..b2863146 100644 --- a/include/ledmatrixdisplay.h +++ b/include/ledmatrixdisplay.h @@ -13,6 +13,6 @@ void refreshTheMatrixDisplay(bool nextPage = false); void DrawNumber(String strNum, uint8_t iDotPos = 0); uint8_t GetCharFromFont(char cChar); uint8_t GetCharWidth(char cChar); -void ScrollLeft(uint8_t *buf, const uint16_t cols, const uint16_t rows); +void ScrollMatrixLeft(uint8_t *buf, const uint16_t cols, const uint16_t rows); #endif \ No newline at end of file diff --git a/src/ledmatrixdisplay.cpp b/src/ledmatrixdisplay.cpp index 881f57fe..e33ea6e0 100644 --- a/src/ledmatrixdisplay.cpp +++ b/src/ledmatrixdisplay.cpp @@ -94,7 +94,7 @@ void refreshTheMatrixDisplay(bool nextPage) { if (col < (LED_MATRIX_WIDTH - 1)) col++; else - ScrollLeft(displaybuf, LED_MATRIX_WIDTH, LED_MATRIX_HEIGHT); + ScrollMatrixLeft(displaybuf, LED_MATRIX_WIDTH, LED_MATRIX_HEIGHT); } else matrix.drawPoint(col, row, 0); // clear current dot @@ -204,7 +204,7 @@ uint8_t GetCharWidth(char cChar) { return CharDescriptor.width; } -void ScrollLeft(uint8_t *buf, const uint16_t cols, const uint16_t rows) { +void ScrollMatrixLeft(uint8_t *buf, const uint16_t cols, const uint16_t rows) { uint32_t i, k, idx; const uint32_t x = cols / 8; From e38a91162b9b670b12df95a07bfefafe3b51bb50 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 30 Sep 2019 19:45:31 +0200 Subject: [PATCH 38/92] no startup screen while rebooting to OTA --- src/main.cpp | 2 +- src/ota.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a23b2b52..79b692ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -200,7 +200,7 @@ void setup() { #ifdef HAS_DISPLAY strcat_P(features, " OLED"); DisplayIsOn = cfg.screenon; - init_display(); // note: blocking call + init_display(!cfg.runmode); // note: blocking call #endif #ifdef BOARD_HAS_PSRAM diff --git a/src/ota.cpp b/src/ota.cpp index 416a4d93..f27b4a8c 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -48,15 +48,13 @@ void start_ota_update() { switch_LED(LED_ON); -#ifdef HAS_DISPLAY - // init display +#ifdef HAS_DISPLAY #ifndef DISPLAY_FLIP oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 400000L); #else oledInit(OLED_128x64, ANGLE_FLIPY, false, -1, -1, 400000L); #endif - oledFill(0, 1); dp_printf(0, 0, 0, 1, "SOFTWARE UPDATE"); dp_printf(0, 1, 0, 0, "WiFi connect .."); @@ -64,6 +62,7 @@ void start_ota_update() { dp_printf(0, 3, 0, 0, "Fetching .."); dp_printf(0, 4, 0, 0, "Downloading .."); dp_printf(0, 5, 0, 0, "Rebooting .."); + oledDumpBuffer(NULL); #endif ESP_LOGI(TAG, "Starting Wifi OTA update"); @@ -157,7 +156,7 @@ int do_ota_update() { client.setCACert(bintray.getCertificate(currentHost)); client.setTimeout(RESPONSE_TIMEOUT_MS); - if (!client.connect(currentHost.c_str(), port, RESPONSE_TIMEOUT_MS)) { + if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str()); ota_display(3, " E", "connection lost"); goto abort; @@ -167,7 +166,7 @@ int do_ota_update() { if (currentHost != prevHost) { client.stop(); client.setCACert(bintray.getCertificate(currentHost)); - if (!client.connect(currentHost.c_str(), port, RESPONSE_TIMEOUT_MS)) { + if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s", currentHost.c_str()); ota_display(3, " E", "server error"); @@ -316,6 +315,7 @@ void ota_display(const uint8_t row, const std::string status, dp_printf(0, 7, 0, 0, " "); dp_printf(0, 7, 0, 0, msg.substr(0, 16).c_str()); } + oledDumpBuffer(NULL); #endif } From 66af2b8c545dfd3282dca3b93e9389904bd42c67 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 1 Oct 2019 13:02:30 +0200 Subject: [PATCH 39/92] pax curve plotter (experimental) --- README.md | 8 +- include/display.h | 15 +++- src/display.cpp | 200 +++++++++++++++++++++++++++++++++------------- 3 files changed, 163 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index eaea51cd..96ef762d 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,13 @@ Paxcounter generates identifiers for sniffed MAC adresses and collects them temp # Display -If you're using a device with OLED display, or if you add such one to the I2C bus, the device shows live data on the display. You can flip between pages showing pax, time, GPS and BME sensor data by pressing the button of the device. +If you're using a device with OLED display, or if you add such one to the I2C bus, the device shows live data on the display. You can flip display pages showing +- recent count of pax +- histogram +- GPS data +- BME sensor data +- Time of day +by pressing the button of the device. # Sensors and Peripherals diff --git a/include/display.h b/include/display.h index fe1fd995..a2a20eff 100644 --- a/include/display.h +++ b/include/display.h @@ -7,10 +7,17 @@ extern uint8_t DisplayIsOn; void refreshTheDisplay(bool nextPage = false); -void init_display(void); +void init_display(uint8_t verbose = 0); void draw_page(time_t t, uint8_t page); -void dp_printf(int x, int y, int font, int inv, const char *format, ...); -void dp_printqr(int offset_x, int offset_y, const char *Message); -void oledfillRect(int x, int y, int width, int height, int bRender); +void dp_printf(uint16_t x, uint16_t y, uint8_t font, uint8_t inv, + const char *format, ...); +void dp_printqr(uint16_t offset_x, uint16_t offset_y, const char *Message); +void oledfillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, + uint8_t bRender); +void oledScrollBufferLeft(uint8_t *buf, const uint16_t width, + const uint16_t height); +int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y, + const uint8_t dot); +void oledPlotCurve(uint16_t count); #endif \ No newline at end of file diff --git a/src/display.cpp b/src/display.cpp index 6a3b5e47..8b7564e1 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -37,23 +37,29 @@ FONT_STRETCHED: 16x32px = 8 chars / line // local Tag for logging static const char TAG[] = __FILE__; +#define DISPLAY_PAGES (5) // number of paxcounter display pages + // settings for oled display library -#define DISPLAY_PAGES (4) // number of display pages -#define USE_BACKBUFFER // for display library +#define USE_BACKBUFFER // settings for qr code generator #define QR_VERSION 3 // 29 x 29px #define QR_SCALEFACTOR 2 // 29 -> 58x < 64px -// helper arry for converting month values to text +// settings for curve plotter +#define PLOT_SCALEFACTOR 1 // downscales pax numbers to display rows +#define DISPLAY_WIDTH 128 // Width in pixels of OLED-display, must be 32X +#define DISPLAY_HEIGHT 64 // Height in pixels of OLED-display, must be 16X + +// helper array for converting month values to text const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - uint8_t DisplayIsOn = 0; +uint8_t displaybuf[DISPLAY_WIDTH * DISPLAY_HEIGHT / 8] = {0}; QRCode qrcode; -void init_display(void) { +void init_display(uint8_t verbose) { // block i2c bus access if (!I2C_MUTEX_LOCK()) @@ -71,56 +77,61 @@ void init_display(void) { oledSetContrast(DISPLAYCONTRAST); oledFill(0, 1); - // show startup screen - // to come -> display .bmp file with logo + if (verbose) { + + // show startup screen + // to come -> display .bmp file with logo // show chip information #if (VERBOSE) - esp_chip_info_t chip_info; - esp_chip_info(&chip_info); - dp_printf(0, 0, 0, 0, "** PAXCOUNTER **"); - dp_printf(0, 1, 0, 0, "Software v%s", PROGVERSION); - dp_printf(0, 3, 0, 0, "ESP32 %d cores", chip_info.cores); - dp_printf(0, 4, 0, 0, "Chip Rev.%d", chip_info.revision); - dp_printf(0, 5, 0, 0, "WiFi%s%s", - (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", - (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); - dp_printf(0, 6, 0, 0, "%dMB %s Flash", - spi_flash_get_chip_size() / (1024 * 1024), - (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext."); + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + dp_printf(0, 0, 0, 0, "** PAXCOUNTER **"); + dp_printf(0, 1, 0, 0, "Software v%s", PROGVERSION); + dp_printf(0, 3, 0, 0, "ESP32 %d cores", chip_info.cores); + dp_printf(0, 4, 0, 0, "Chip Rev.%d", chip_info.revision); + dp_printf(0, 5, 0, 0, "WiFi%s%s", + (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); + dp_printf(0, 6, 0, 0, "%dMB %s Flash", + spi_flash_get_chip_size() / (1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." + : "ext."); - // give user some time to read or take picture - oledDumpBuffer(NULL); - delay(2000); - oledFill(0x00, 1); + // give user some time to read or take picture + oledDumpBuffer(NULL); + delay(2000); + oledFill(0x00, 1); #endif // VERBOSE #if (HAS_LORA) - // generate DEVEUI as QR code and text - uint8_t buf[8]; - char deveui[17]; - os_getDevEui((u1_t *)buf); - sprintf(deveui, "%016llX", *((uint64_t *)&buf)); + // generate DEVEUI as QR code and text + uint8_t buf[8]; + char deveui[17]; + os_getDevEui((u1_t *)buf); + sprintf(deveui, "%016llX", *((uint64_t *)&buf)); - // display DEVEUI as QR code on the left - oledSetContrast(30); - dp_printqr(3, 3, deveui); + // display DEVEUI as QR code on the left + oledSetContrast(30); + dp_printqr(3, 3, deveui); - // display DEVEUI as plain text on the right - dp_printf(72, 0, FONT_NORMAL, 0, "LORAWAN"); - dp_printf(72, 1, FONT_NORMAL, 0, "DEVEUI:"); - dp_printf(80, 3, FONT_NORMAL, 0, "%4.4s", deveui); - dp_printf(80, 4, FONT_NORMAL, 0, "%4.4s", deveui + 4); - dp_printf(80, 5, FONT_NORMAL, 0, "%4.4s", deveui + 8); - dp_printf(80, 6, FONT_NORMAL, 0, "%4.4s", deveui + 12); + // display DEVEUI as plain text on the right + dp_printf(72, 0, FONT_NORMAL, 0, "LORAWAN"); + dp_printf(72, 1, FONT_NORMAL, 0, "DEVEUI:"); + dp_printf(80, 3, FONT_NORMAL, 0, "%4.4s", deveui); + dp_printf(80, 4, FONT_NORMAL, 0, "%4.4s", deveui + 4); + dp_printf(80, 5, FONT_NORMAL, 0, "%4.4s", deveui + 8); + dp_printf(80, 6, FONT_NORMAL, 0, "%4.4s", deveui + 12); - // give user some time to read or take picture - oledDumpBuffer(NULL); - delay(8000); - oledSetContrast(DISPLAYCONTRAST); - oledFill(0x00, 1); + // give user some time to read or take picture + oledDumpBuffer(NULL); + delay(8000); + oledSetContrast(DISPLAYCONTRAST); + oledFill(0x00, 1); #endif // HAS_LORA + } // verbose + oledPower(cfg.screenon); // set display off if disabled I2C_MUTEX_UNLOCK(); // release i2c bus access @@ -171,15 +182,20 @@ void draw_page(time_t t, uint8_t page) { // line 1/2: pax counter dp_printf(0, 0, FONT_STRETCHED, 0, "PAX:%-4d", - (int)macs.size()); // display number of unique macs total Wifi + BLE + macs.size()); // display number of unique macs total Wifi + BLE + + // update histogram if we have a display + oledPlotCurve(macs.size()); switch (page % DISPLAY_PAGES) { // page 0: parameters overview - // page 1: time + // page 1: pax graph // page 2: GPS // page 3: BME280/680 + // page 4: time + // page 0: parameters overview case 0: // line 3: wifi + bluetooth counters @@ -194,7 +210,9 @@ void draw_page(time_t t, uint8_t page) { // line 4: Battery + GPS status + Wifi channel #if (defined BAT_MEASURE_ADC || defined HAS_PMU) if (batt_voltage == 0xffff) - dp_printf(0, 4, FONT_SMALL, 0, "%s", "B:USB "); + dp_printf(0, 4, FONT_SMALL, 0, "%s", "USB "); + else if (batt_voltage == 0) + dp_printf(0, 4, FONT_SMALL, 0, "%s", "No batt"); else dp_printf(0, 4, FONT_SMALL, 0, "B:%.2fV", batt_voltage / 1000.0); #endif @@ -249,11 +267,12 @@ void draw_page(time_t t, uint8_t page) { break; // page0 + // page 1: pax graph case 1: - dp_printf(0, 4, FONT_LARGE, 0, "%02d:%02d:%02d", hour(t), minute(t), - second(t)); + oledDumpBuffer(displaybuf); break; // page1 + // page 2: GPS case 2: #if (HAS_GPS) if (gps.location.age() < 1500) { @@ -281,6 +300,7 @@ void draw_page(time_t t, uint8_t page) { break; // page2 + // page 3: BME280/680 case 3: #if (HAS_BME) @@ -301,6 +321,13 @@ void draw_page(time_t t, uint8_t page) { break; // page3 + // page 4: time + case 4: + + dp_printf(0, 4, FONT_LARGE, 0, "%02d:%02d:%02d", hour(t), minute(t), + second(t)); + break; + default: break; // default @@ -308,8 +335,9 @@ void draw_page(time_t t, uint8_t page) { } // draw_page -// display print helper functions -void dp_printf(int x, int y, int font, int inv, const char *format, ...) { +// display helper functions +void dp_printf(uint16_t x, uint16_t y, uint8_t font, uint8_t inv, + const char *format, ...) { char loc_buf[64]; char *temp = loc_buf; va_list arg; @@ -337,13 +365,13 @@ void dp_printf(int x, int y, int font, int inv, const char *format, ...) { } } -void dp_printqr(int offset_x, int offset_y, const char *Message) { +void dp_printqr(uint16_t offset_x, uint16_t offset_y, const char *Message) { uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; qrcode_initText(&qrcode, qrcodeData, QR_VERSION, ECC_HIGH, Message); // draw QR code - for (int y = 0; y < qrcode.size; y++) - for (int x = 0; x < qrcode.size; x++) + for (uint16_t y = 0; y < qrcode.size; y++) + for (uint16_t x = 0; x < qrcode.size; x++) if (!qrcode_getModule(&qrcode, x, y)) // "black" oledfillRect(x * QR_SCALEFACTOR + offset_x, y * QR_SCALEFACTOR + offset_y, QR_SCALEFACTOR, @@ -360,9 +388,71 @@ void dp_printqr(int offset_x, int offset_y, const char *Message) { qrcode.size * QR_SCALEFACTOR + 2 * offset_y, false); } -void oledfillRect(int x, int y, int width, int height, int bRender) { - for (int xi = x; xi < x + width; xi++) +void oledfillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, + uint8_t bRender) { + for (uint16_t xi = x; xi < x + width; xi++) oledDrawLine(xi, y, xi, y + height - 1, bRender); } +int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y, + const uint8_t dot) { + + uint8_t page, bit; + + if (x > DISPLAY_WIDTH || y > DISPLAY_HEIGHT) + return -1; + + page = y / 8; + bit = y % 8; + + if (dot) + buf[page * DISPLAY_WIDTH + x] |= (1 << bit); // mark + else + buf[page * DISPLAY_WIDTH + x] &= ~(0 << bit); // clear + + return 0; +} + +void oledScrollBufferLeft(uint8_t *buf, const uint16_t width, + const uint16_t height) { + + uint16_t col, page, idx; + + for (page = 0; page < height / 8; page++) { + for (col = 0; col < width - 1; col++) { + idx = page * width + col; + buf[idx] = buf[idx + 1]; + } + buf[idx + 1] = 0; + } +} + +void oledPlotCurve(uint16_t count) { + + uint8_t level; + static uint16_t last_count = 0, col = 0, row = 0; + + if (last_count == count) + return; + + // next count cycle? + if (count == 0) { + + // matrix full? then scroll left 1 dot, else increment column + if (col < DISPLAY_WIDTH - 1) + col++; + else + oledScrollBufferLeft(displaybuf, DISPLAY_WIDTH, DISPLAY_HEIGHT); + + } else + oledDrawPixel(displaybuf, col, row, 0); // clear current dot + + // scale and set new dot + last_count = count; + level = count / PLOT_SCALEFACTOR; + row = + level <= DISPLAY_HEIGHT ? DISPLAY_HEIGHT - 1 - level % DISPLAY_HEIGHT : 0; + oledDrawPixel(displaybuf, col, row, 1); +} + #endif // HAS_DISPLAY \ No newline at end of file From be01760c32a00276e2d7c9f526b97d7e1b249743 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 1 Oct 2019 13:35:05 +0200 Subject: [PATCH 40/92] pax curve plotter --- src/display.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index 8b7564e1..9662dc3f 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -397,18 +397,15 @@ void oledfillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y, const uint8_t dot) { - uint8_t page, bit; - if (x > DISPLAY_WIDTH || y > DISPLAY_HEIGHT) return -1; - page = y / 8; - bit = y % 8; + uint8_t bit = y & 7; + uint16_t idx = y / 8 * DISPLAY_WIDTH + x; + buf[idx] &= ~(1 << bit); // clear pixel if (dot) - buf[page * DISPLAY_WIDTH + x] |= (1 << bit); // mark - else - buf[page * DISPLAY_WIDTH + x] &= ~(0 << bit); // clear + buf[idx] |= (1 << bit); // set pixel return 0; } From bae583934a9591ff9a6ecfa05b6b8e444b0e0328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Brandm=C3=BCller?= Date: Tue, 1 Oct 2019 15:44:12 +0200 Subject: [PATCH 41/92] add oled library to platformio.ini --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index ded8baf9..a8f69ac1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -59,6 +59,7 @@ lib_deps_lora = lib_deps_display = ss_oled@>=2.1.1 BitBang_I2C@>=1.2.0 + QRCode@>=0.0.1 lib_deps_matrix_display = https://github.com/Seeed-Studio/Ultrathin_LED_Matrix.git lib_deps_rgbled = From 0440e536dde6835aee727ef2c12742a997633b20 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 1 Oct 2019 18:06:49 +0200 Subject: [PATCH 42/92] scalefactor for curve plotter --- include/cyclic.h | 5 +++++ include/display.h | 2 +- include/senddata.h | 7 ++++++- src/cyclic.cpp | 4 ++++ src/display.cpp | 41 +++++++++++++++++++++-------------------- src/senddata.cpp | 4 ++++ 6 files changed, 41 insertions(+), 22 deletions(-) diff --git a/include/cyclic.h b/include/cyclic.h index b9512c53..4b402360 100644 --- a/include/cyclic.h +++ b/include/cyclic.h @@ -5,6 +5,7 @@ #include "senddata.h" #include "rcommand.h" #include "spislave.h" + #if(HAS_LORA) #include #endif @@ -13,6 +14,10 @@ #include "bmesensor.h" #endif +#ifdef HAS_DISPLAY +#include "display.h" +#endif + extern Ticker housekeeper; void housekeeping(void); diff --git a/include/display.h b/include/display.h index a2a20eff..7c90a968 100644 --- a/include/display.h +++ b/include/display.h @@ -18,6 +18,6 @@ void oledScrollBufferLeft(uint8_t *buf, const uint16_t width, const uint16_t height); int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y, const uint8_t dot); -void oledPlotCurve(uint16_t count); +void oledPlotCurve(uint16_t count, bool reset); #endif \ No newline at end of file diff --git a/include/senddata.h b/include/senddata.h index 4a748445..0151f7e2 100644 --- a/include/senddata.h +++ b/include/senddata.h @@ -2,10 +2,15 @@ #define _SENDDATA_H #include "spislave.h" +#include "cyclic.h" + #if(HAS_LORA) #include "lorawan.h" #endif -#include "cyclic.h" + +#ifdef HAS_DISPLAY +#include "display.h" +#endif extern Ticker sendcycler; diff --git a/src/cyclic.cpp b/src/cyclic.cpp index ef2ce200..9b75ecef 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -128,5 +128,9 @@ void reset_counters() { macs_total = 0; // reset all counters macs_wifi = 0; macs_ble = 0; +#ifdef HAS_DISPLAY + oledPlotCurve(0, true); +#endif + #endif } \ No newline at end of file diff --git a/src/display.cpp b/src/display.cpp index 9662dc3f..01057745 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -47,9 +47,8 @@ static const char TAG[] = __FILE__; #define QR_SCALEFACTOR 2 // 29 -> 58x < 64px // settings for curve plotter -#define PLOT_SCALEFACTOR 1 // downscales pax numbers to display rows -#define DISPLAY_WIDTH 128 // Width in pixels of OLED-display, must be 32X -#define DISPLAY_HEIGHT 64 // Height in pixels of OLED-display, must be 16X +#define DISPLAY_WIDTH 128 // Width in pixels of OLED-display, must be 32X +#define DISPLAY_HEIGHT 64 // Height in pixels of OLED-display, must be 16X // helper array for converting month values to text const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -185,7 +184,7 @@ void draw_page(time_t t, uint8_t page) { macs.size()); // display number of unique macs total Wifi + BLE // update histogram if we have a display - oledPlotCurve(macs.size()); + oledPlotCurve(macs.size(), false); switch (page % DISPLAY_PAGES) { @@ -424,31 +423,33 @@ void oledScrollBufferLeft(uint8_t *buf, const uint16_t width, } } -void oledPlotCurve(uint16_t count) { +void oledPlotCurve(uint16_t count, bool reset) { - uint8_t level; - static uint16_t last_count = 0, col = 0, row = 0; + static uint16_t last_count = 0, col = 0, row = 0, scalefactor = 1; - if (last_count == count) + if ((last_count == count) && !reset) return; - // next count cycle? - if (count == 0) { - - // matrix full? then scroll left 1 dot, else increment column - if (col < DISPLAY_WIDTH - 1) + if (reset) { // next count cycle? + if (col < DISPLAY_WIDTH - 1) // matrix not full -> increment column col++; - else + else // matrix full -> scroll left 1 dot oledScrollBufferLeft(displaybuf, DISPLAY_WIDTH, DISPLAY_HEIGHT); - } else - oledDrawPixel(displaybuf, col, row, 0); // clear current dot + } else // clear current dot + oledDrawPixel(displaybuf, col, row, 0); - // scale and set new dot + // re-scale, if necessary + while (((count / scalefactor) <= DISPLAY_HEIGHT) && (scalefactor > 1)) { + scalefactor--; + } + while ((count / scalefactor) > DISPLAY_HEIGHT) { + scalefactor++; + } + + // set new dot + row = DISPLAY_HEIGHT - 1 - (count / scalefactor) % DISPLAY_HEIGHT; last_count = count; - level = count / PLOT_SCALEFACTOR; - row = - level <= DISPLAY_HEIGHT ? DISPLAY_HEIGHT - 1 - level % DISPLAY_HEIGHT : 0; oledDrawPixel(displaybuf, col, row, 1); } diff --git a/src/senddata.cpp b/src/senddata.cpp index 76d412e2..11b0d81a 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -75,6 +75,10 @@ void sendData() { get_salt(); // get new salt for salting hashes ESP_LOGI(TAG, "Counter cleared"); } +#ifdef HAS_DISPLAY + else + oledPlotCurve(macs.size(), true); +#endif break; #endif From 1bf8898c4e9694464581283e811e43681cd35803 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Tue, 1 Oct 2019 18:08:24 +0200 Subject: [PATCH 43/92] platformio.ini update --- platformio.ini | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/platformio.ini b/platformio.ini index ded8baf9..51fb94c8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -7,7 +7,7 @@ ; ---> SELECT THE TARGET PLATFORM HERE! <--- [board] -halfile = generic.h +;halfile = generic.h ;halfile = ebox.h ;halfile = eboxtube.h ;halfile = ecopower.h @@ -18,7 +18,7 @@ halfile = generic.h ;halfile = ttgov21old.h ;halfile = ttgov21new.h ;halfile = ttgofox.h -;halfile = ttgobeam.h +halfile = ttgobeam.h ;halfile = ttgobeam10.h ;halfile = fipy.h ;halfile = lopy.h @@ -34,16 +34,16 @@ halfile = generic.h [platformio] ; upload firmware to board with usb cable -default_envs = usb +;default_envs = usb ; upload firmware to a jfrog bintray repository ;default_envs = ota ; use latest versions of libraries -;default_envs = dev +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 = 1.8.4 +release_version = 1.8.5 ; 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 @@ -51,14 +51,15 @@ extra_scripts = pre:build.py otakeyfile = ota.conf lorakeyfile = loraconf.h lmicconfigfile = lmic_config.h -platform_espressif32 = espressif32@1.10.0 +platform_espressif32 = espressif32@1.9.0 monitor_speed = 115200 upload_speed = 115200 lib_deps_lora = MCCI LoRaWAN LMIC library@>=3.0.99 lib_deps_display = - ss_oled@>=2.1.1 + ss_oled@>=2.2.1 BitBang_I2C@>=1.2.0 + QRCode@>=0.0.1 lib_deps_matrix_display = https://github.com/Seeed-Studio/Ultrathin_LED_Matrix.git lib_deps_rgbled = @@ -67,14 +68,14 @@ lib_deps_gps = 1655@>=1.0.2 ;TinyGPSPlus by Mikal Hart lib_deps_sensors = Adafruit Unified Sensor@>=1.0.3 - Adafruit BME280 Library@>=1.0.9 + Adafruit BME280 Library@>=1.0.10 lib_deps_basic = ArduinoJson@^5.13.1 76@>=1.2.2 ;Timezone by Jack Christensen 274@>=2.3.3 ;RTC by Michael Miller SimpleButton - ;AXP202X_Library@^1.0.1 - https://github.com/lewisxhe/AXP202X_Library.git#8045ddf + ;AXP202X_Library@>=1.0.1 + https://github.com/lewisxhe/AXP202X_Library.git lib_deps_all = ${common.lib_deps_basic} ${common.lib_deps_lora} From f86bfaefb66228d07c3d25eed92ffaa3e7e447cd Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 3 Sep 2019 16:28:11 +0200 Subject: [PATCH 44/92] extract timezone from time sync answer and add to UTC timestamp --- include/timesync.h | 4 ++-- src/timesync.cpp | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/timesync.h b/include/timesync.h index c102c1c4..82da84f7 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -7,7 +7,7 @@ #include "timekeeper.h" //#define TIME_SYNC_TRIGGER 100 // threshold for time sync [milliseconds] -#define TIME_SYNC_FRAME_LENGTH 0x05 // timeserver answer frame length [bytes] +#define TIME_SYNC_FRAME_LENGTH 0x07 // timeserver answer frame length [bytes] #define TIME_SYNC_FIXUP 4 // calibration to fixup processing time [milliseconds] void timesync_init(void); @@ -16,4 +16,4 @@ int recv_timesync_ans(const uint8_t seq_no, const uint8_t buf[], const uint8_t b void process_timesync_req(void *taskparameter); void store_time_sync_req(uint32_t t_millisec); -#endif \ No newline at end of file +#endif diff --git a/src/timesync.cpp b/src/timesync.cpp index 8ce3238f..6c60a225 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -177,9 +177,14 @@ int recv_timesync_ans(const uint8_t seq_no, const uint8_t buf[], const uint8_t b // 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 containing UTC seconds since unix epoch, msb + uint16_t timestamp_msec = 4 * buf[6]; + // pointers to 4 bytes 4 bytes containing UTC seconds since unix epoch, msb uint32_t timestamp_sec, *timestamp_ptr; + uint32_t timezone_sec; + + // extract timezone from buffer (in 15min steps, one step being 15min * 60s = 900s) + timezone_sec = buf[0]*900; + buf++; // convert buffer to uint32_t, octet order is big endian timestamp_ptr = (uint32_t *)buf; @@ -187,7 +192,7 @@ int recv_timesync_ans(const uint8_t seq_no, const uint8_t buf[], const uint8_t b timestamp_sec = __builtin_bswap32(*timestamp_ptr); // construct the timepoint when message was seen on gateway - time_sync_rx[k] += seconds(timestamp_sec) + milliseconds(timestamp_msec); + time_sync_rx[k] += seconds(timestamp_sec+timezone_sec) + milliseconds(timestamp_msec); // we guess timepoint is recent if it newer than code compile date if (timeIsValid(myClock::to_time_t(time_sync_rx[k]))) { From 08c5a0ffe95a7e04d99c84f90d379a2bcde2b805 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 4 Oct 2019 14:47:58 +0200 Subject: [PATCH 45/92] uploadspeed ebox.h & eboxtube.h --- src/hal/ebox.h | 2 +- src/hal/eboxtube.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hal/ebox.h b/src/hal/ebox.h index ebd70136..6da29292 100644 --- a/src/hal/ebox.h +++ b/src/hal/ebox.h @@ -1,5 +1,5 @@ // clang-format off -// upload_speed 115200 +// upload_speed 921600 // board esp32dev #ifndef _EBOX_H diff --git a/src/hal/eboxtube.h b/src/hal/eboxtube.h index 34abe865..86a69d7d 100644 --- a/src/hal/eboxtube.h +++ b/src/hal/eboxtube.h @@ -1,5 +1,5 @@ // clang-format off -// upload_speed 115200 +// upload_speed 921600 // board esp32dev From ba732012b9d251c0e2591941a628f73bce8e4636 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Fri, 4 Oct 2019 15:31:31 +0200 Subject: [PATCH 46/92] move timesync seq_no into message body from port --- include/timesync.h | 4 +++- src/lorawan.cpp | 4 ++-- src/paxcounter.conf | 8 ++++---- src/timesync.cpp | 15 +++++++++------ 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/timesync.h b/include/timesync.h index 82da84f7..8b8c42bc 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -12,7 +12,9 @@ void timesync_init(void); void send_timesync_req(void); -int recv_timesync_ans(const uint8_t seq_no, const uint8_t buf[], const uint8_t buf_len); + +int recv_timesync_ans(const uint8_t buf[], uint8_t buf_len); + void process_timesync_req(void *taskparameter); void store_time_sync_req(uint32_t t_millisec); diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 088d4305..e6aa7114 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -561,8 +561,8 @@ void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg, #if (TIME_SYNC_LORASERVER) // valid timesync answer -> call timesync processor - if ((port >= TIMEANSWERPORT_MIN) && (port <= TIMEANSWERPORT_MAX)) { - recv_timesync_ans(port, pMsg, nMsg); + if (port == TIMEPORT) { + recv_timesync_ans(pMsg, nMsg); break; } #endif diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 40852f59..f7826a9a 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -30,7 +30,7 @@ * |< Scan Window > |< Scan Window > | ... |< Scan Window > | * |< Scan Interval >|< Scan Interval >| ... |< Scan Interval >| * |< Scan duration >| -* +* * Scan duration sets how long scanning should be going on, before starting a new scan cycle. 0 means infinite (default). * Scan window sets how much of the interval should be occupied by scanning. Should be >= BLESCANINTERVAL. * Scan interval is how long scanning should be done on each channel. BLE uses 3 channels for advertising. @@ -97,9 +97,9 @@ #define BEACONPORT 6 // beacon alarms #define BMEPORT 7 // BME680 sensor #define BATTPORT 8 // battery voltage -#define TIMEPORT 9 // time query -#define TIMEANSWERPORT_MIN 0xA0 // time answer, start of port range -#define TIMEANSWERPORT_MAX 0xDF // time answer, end of port range +#define TIMEPORT 9 // time query and response +#define TIMEDIFFPORT 13 // time adjust diff +#define TIMEREQUEST_MAX_SEQNO 250 // time answer, start of port range #define SENSOR1PORT 10 // user sensor #1 #define SENSOR2PORT 11 // user sensor #2 #define SENSOR3PORT 12 // user sensor #3 diff --git a/src/timesync.cpp b/src/timesync.cpp index 6c60a225..a50d7ca1 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -25,7 +25,7 @@ typedef std::chrono::duration> TaskHandle_t timeSyncReqTask = NULL; -static uint8_t time_sync_seqNo = random(TIMEANSWERPORT_MIN, TIMEANSWERPORT_MAX); +static uint8_t time_sync_seqNo = 0; static bool timeSyncPending = false; static myClock_timepoint time_sync_tx[TIME_SYNC_SAMPLES]; static myClock_timepoint time_sync_rx[TIME_SYNC_SAMPLES]; @@ -93,9 +93,10 @@ void process_timesync_req(void *taskparameter) { time_point_cast(time_sync_tx[k]); // wrap around seqNo, keeping it in time port range - time_sync_seqNo = (time_sync_seqNo < TIMEANSWERPORT_MAX) - ? time_sync_seqNo + 1 - : TIMEANSWERPORT_MIN; + time_sync_seqNo++; + if(time_sync_seqNo > TIMEREQUEST_MAX_SEQNO) { + time_sync_seqNo = 0; + } if (i < TIME_SYNC_SAMPLES - 1) { // wait until next cycle @@ -154,7 +155,9 @@ void store_time_sync_req(uint32_t timestamp) { } // process timeserver timestamp answer, called from lorawan.cpp -int recv_timesync_ans(const uint8_t seq_no, const uint8_t buf[], const uint8_t buf_len) { +int recv_timesync_ans(const uint8_t buf[], const uint8_t buf_len) { + uint8_t seq_no = buf[0]; + buf++; // if no timesync handshake is pending then exit if (!timeSyncPending) @@ -223,4 +226,4 @@ void timesync_init() { 1); // CPU core } -#endif \ No newline at end of file +#endif From 5fcb33d03d353f15db180833f6170deddbc2bee7 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Tue, 1 Oct 2019 17:28:54 +0200 Subject: [PATCH 47/92] node red server by cyberman with seq no in payload, not in port, and timezone (diff minimized) --- src/Timeserver/Nodered-Timeserver.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index 85e52607..3319b39d 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -187,7 +187,7 @@ "type": "function", "z": "449c1517.e25f4c", "name": "Timeserver Logic", - "func": "/* LoRaWAN Timeserver\n\nconstruct 5 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\nFPort = sequence number (taken from node's time_sync_req)\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload.payload_raw[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(5);\nnew DataView(buf).setUint32(0, seconds);\nnew DataView(buf).setUint8(4, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = seqNo;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", + "func": "/* LoRaWAN Timeserver\n\nconstruct 5 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\nFPort = sequence number (taken from node's time_sync_req)\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(7);\nnew DataView(buf).setUint8(0, seqNo);\n// Timezone (in 15min steps)\nvar timezone = 8; // CET = UTC+2h\nnew DataView(buf).setUint8(1, timezone);\nnew DataView(buf).setUint32(2, seconds);\nnew DataView(buf).setUint8(6, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", "outputs": 5, "noerr": 0, "x": 350, @@ -384,4 +384,4 @@ "disabled": false, "hidden": false } -] \ No newline at end of file +] From c56c973534f912617cd4a772dd78449b8a0e28c9 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 4 Oct 2019 15:47:33 +0200 Subject: [PATCH 48/92] curve plotter (experimental) --- include/display.h | 1 + src/display.cpp | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/include/display.h b/include/display.h index 7c90a968..591814ba 100644 --- a/include/display.h +++ b/include/display.h @@ -19,5 +19,6 @@ void oledScrollBufferLeft(uint8_t *buf, const uint16_t width, int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y, const uint8_t dot); void oledPlotCurve(uint16_t count, bool reset); +void oledRescaleBuffer(uint8_t *buf, const int factor); #endif \ No newline at end of file diff --git a/src/display.cpp b/src/display.cpp index 01057745..5770cabc 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -48,7 +48,7 @@ static const char TAG[] = __FILE__; // settings for curve plotter #define DISPLAY_WIDTH 128 // Width in pixels of OLED-display, must be 32X -#define DISPLAY_HEIGHT 64 // Height in pixels of OLED-display, must be 16X +#define DISPLAY_HEIGHT 64 // Height in pixels of OLED-display, must be 64X // helper array for converting month values to text const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -252,15 +252,15 @@ void draw_page(time_t t, uint8_t page) { // LMiC event display, display inverse if sendqueue not empty msgWaiting = uxQueueMessagesWaiting(LoraSendQueue); if (msgWaiting) - dp_printf(0, 7, FONT_SMALL, 1, "%-17s", lmic_event_msg); + dp_printf(0, 7, FONT_SMALL, 1, "%-16s", lmic_event_msg); else - dp_printf(0, 7, FONT_SMALL, 0, "%-17s", lmic_event_msg); + dp_printf(0, 7, FONT_SMALL, 0, "%-16s", lmic_event_msg); // LORA datarate, display inverse if ADR disabled if (cfg.adrmode) - dp_printf(108, 7, FONT_SMALL, 0, "%-4s", + dp_printf(100, 7, FONT_SMALL, 0, "%-4s", getSfName(updr2rps(LMIC.datarate))); else - dp_printf(108, 7, FONT_SMALL, 1, "%-4s", + dp_printf(100, 7, FONT_SMALL, 1, "%-4s", getSfName(updr2rps(LMIC.datarate))); #endif // HAS_LORA @@ -425,7 +425,8 @@ void oledScrollBufferLeft(uint8_t *buf, const uint16_t width, void oledPlotCurve(uint16_t count, bool reset) { - static uint16_t last_count = 0, col = 0, row = 0, scalefactor = 1; + static uint16_t last_count = 0, col = 0, row = 0; + static int scalefactor = 1, oldsf = 1; if ((last_count == count) && !reset) return; @@ -440,12 +441,13 @@ void oledPlotCurve(uint16_t count, bool reset) { oledDrawPixel(displaybuf, col, row, 0); // re-scale, if necessary - while (((count / scalefactor) <= DISPLAY_HEIGHT) && (scalefactor > 1)) { + oldsf = scalefactor; + while (((count / scalefactor) <= DISPLAY_HEIGHT) && (scalefactor > 1)) scalefactor--; - } - while ((count / scalefactor) > DISPLAY_HEIGHT) { + while ((count / scalefactor) > DISPLAY_HEIGHT) scalefactor++; - } + if (scalefactor != oldsf) + oledRescaleBuffer(displaybuf, scalefactor); // set new dot row = DISPLAY_HEIGHT - 1 - (count / scalefactor) % DISPLAY_HEIGHT; @@ -453,4 +455,27 @@ void oledPlotCurve(uint16_t count, bool reset) { oledDrawPixel(displaybuf, col, row, 1); } +void oledRescaleBuffer(uint8_t *buf, const int factor) { + + if (!factor) + return; + + uint64_t buf_col; + + for (uint16_t col = 0; col < DISPLAY_WIDTH; col++) { + // convert column bytes from display buffer to uint64_t + buf_col = *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8]; + + if (factor < 0) + // shift left: scroll up = scale down + buf_col <= abs(factor); + else + // shift right: scroll down = scale up + buf_col >= abs(factor); + + // write back uint64_t to uint8_t display buffer + *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8] = buf_col; + } +} + #endif // HAS_DISPLAY \ No newline at end of file From 00761c77b37ae639bd7c65b0eb87684d7366e84f Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 4 Oct 2019 15:48:00 +0200 Subject: [PATCH 49/92] readme.md cleanup --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 96ef762d..53f08126 100644 --- a/README.md +++ b/README.md @@ -318,8 +318,8 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. Example for EU868: DataRate Configuration Bit/s - 0 LoRa: SF12 / 125 kHz 250 - 1 LoRa: SF11 / 125 kHz 440 + 0 LoRa: SF12 / 125 kHz 250 + 1 LoRa: SF11 / 125 kHz 440 2 LoRa: SF10 / 125 kHz 980 3 LoRa: SF9 / 125 kHz 1760 4 LoRa: SF8 / 125 kHz 3125 From be8ce87a4a41a38f63bfc32da3f5ee1699871110 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 4 Oct 2019 15:49:22 +0200 Subject: [PATCH 50/92] platformio.ini: lib versions update --- platformio.ini | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/platformio.ini b/platformio.ini index 51fb94c8..1df56f70 100644 --- a/platformio.ini +++ b/platformio.ini @@ -7,7 +7,7 @@ ; ---> SELECT THE TARGET PLATFORM HERE! <--- [board] -;halfile = generic.h +halfile = generic.h ;halfile = ebox.h ;halfile = eboxtube.h ;halfile = ecopower.h @@ -18,7 +18,7 @@ ;halfile = ttgov21old.h ;halfile = ttgov21new.h ;halfile = ttgofox.h -halfile = ttgobeam.h +;halfile = ttgobeam.h ;halfile = ttgobeam10.h ;halfile = fipy.h ;halfile = lopy.h @@ -38,12 +38,12 @@ halfile = ttgobeam.h ; upload firmware to a jfrog bintray repository ;default_envs = ota ; use latest versions of libraries -default_envs = dev +default_envs = usb 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 = 1.8.5 +release_version = 1.8.52 ; 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 @@ -57,7 +57,7 @@ upload_speed = 115200 lib_deps_lora = MCCI LoRaWAN LMIC library@>=3.0.99 lib_deps_display = - ss_oled@>=2.2.1 + ss_oled@>=3.0.0 BitBang_I2C@>=1.2.0 QRCode@>=0.0.1 lib_deps_matrix_display = @@ -74,8 +74,7 @@ lib_deps_basic = 76@>=1.2.2 ;Timezone by Jack Christensen 274@>=2.3.3 ;RTC by Michael Miller SimpleButton - ;AXP202X_Library@>=1.0.1 - https://github.com/lewisxhe/AXP202X_Library.git + AXP202X_Library@>=1.0.1 lib_deps_all = ${common.lib_deps_basic} ${common.lib_deps_lora} From fe71e8e7109302ef28b402c9b73c11c652002c24 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Fri, 4 Oct 2019 17:09:25 +0200 Subject: [PATCH 51/92] seqNo text node fix --- src/Timeserver/Nodered-Timeserver.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index 3319b39d..71f6dc33 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -334,7 +334,7 @@ "height": 0, "name": "Sequence No", "label": "Sequence", - "format": "{{msg.payload}}", + "format": "{{}}", "layout": "col-center", "x": 700, "y": 460, From 3ab2d179379021b226cac47dbd3474e448932636 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Fri, 4 Oct 2019 17:20:57 +0200 Subject: [PATCH 52/92] increase version number of node-red server --- src/Timeserver/Nodered-Timeserver.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index 71f6dc33..54e16064 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -176,7 +176,7 @@ "id": "6190967b.01f758", "type": "comment", "z": "449c1517.e25f4c", - "name": "LoRaWAN Timeserver v1.1", + "name": "LoRaWAN Timeserver v1.2", "info": "PLEASE NOTE: There is a patent filed for the time sync algorithm used in the\ncode of this file. The shown implementation example is covered by the\nrepository's licencse, but you may not be eligible to deploy the applied\nalgorithm in applications without granted license by the patent holder.", "x": 170, "y": 40, @@ -384,4 +384,4 @@ "disabled": false, "hidden": false } -] +] \ No newline at end of file From c46229dd0eda18cede449e9597fd26d768f71b87 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Fri, 4 Oct 2019 17:46:46 +0200 Subject: [PATCH 53/92] node-red code description updated --- src/Timeserver/Nodered-Timeserver.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index 54e16064..63784b4c 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -187,7 +187,7 @@ "type": "function", "z": "449c1517.e25f4c", "name": "Timeserver Logic", - "func": "/* LoRaWAN Timeserver\n\nconstruct 5 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1..4 current second (from epoch time 1970)\n5 1/250ths fractions of current second\n\nFPort = sequence number (taken from node's time_sync_req)\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(7);\nnew DataView(buf).setUint8(0, seqNo);\n// Timezone (in 15min steps)\nvar timezone = 8; // CET = UTC+2h\nnew DataView(buf).setUint8(1, timezone);\nnew DataView(buf).setUint32(2, seconds);\nnew DataView(buf).setUint8(6, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", + "func": "/* LoRaWAN Timeserver\n\nconstruct 7 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1 sequence number (taken from node's time_sync_req)\n2 timezone in 15 minutes steps\n3..6 current second (from epoch time 1970)\n7 1/250ths fractions of current second\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(7);\nnew DataView(buf).setUint8(0, seqNo);\n// Timezone (in 15min steps)\nvar timezone = 8; // CET = UTC+2h\nnew DataView(buf).setUint8(1, timezone);\nnew DataView(buf).setUint32(2, seconds);\nnew DataView(buf).setUint8(6, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", "outputs": 5, "noerr": 0, "x": 350, From 1c24bed38f4dccf1a4b171c5ba33cdc547a48dc8 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 4 Oct 2019 18:17:46 +0200 Subject: [PATCH 54/92] bugfix no curve plot while display is off --- src/display.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index 5770cabc..3eb792c8 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -141,6 +141,9 @@ void refreshTheDisplay(bool nextPage) { static uint8_t DisplayPage = 0; + // update histogram if we have a display + oledPlotCurve(macs.size(), false); + // if display is switched off we don't refresh it to relax cpu if (!DisplayIsOn && (DisplayIsOn == cfg.screenon)) return; @@ -183,9 +186,6 @@ void draw_page(time_t t, uint8_t page) { dp_printf(0, 0, FONT_STRETCHED, 0, "PAX:%-4d", macs.size()); // display number of unique macs total Wifi + BLE - // update histogram if we have a display - oledPlotCurve(macs.size(), false); - switch (page % DISPLAY_PAGES) { // page 0: parameters overview From c37db3d4d3562df749da26ee386c58cd9364fba3 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 5 Oct 2019 13:11:59 +0200 Subject: [PATCH 55/92] Timeserver.json: bugfix missing port 0xff message --- src/Timeserver/Nodered-Timeserver.json | 136 ++++++++++++------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index 63784b4c..6b0cb5ff 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -1,6 +1,6 @@ [ { - "id": "49e3c067.e782e", + "id": "9b4f492d.fbfd18", "type": "change", "z": "449c1517.e25f4c", "name": "Payload", @@ -48,32 +48,32 @@ "from": "", "to": "", "reg": false, - "x": 240, - "y": 513, + "x": 220, + "y": 520, "wires": [ [ - "84f1cda2.069e7" + "53a85e2c.2728d" ] ] }, { - "id": "cc140589.dea168", + "id": "9c105726.613a58", "type": "mqtt in", "z": "449c1517.e25f4c", "name": "listen", "topic": "+/devices/+/up", "qos": "2", "broker": "2a15ab6f.ab2244", - "x": 110, - "y": 120, + "x": 90, + "y": 127, "wires": [ [ - "4f97d75.6c87528" + "113ef524.57edeb" ] ] }, { - "id": "72d5e7ee.d1eba8", + "id": "1c9a7438.6e38ec", "type": "mqtt out", "z": "449c1517.e25f4c", "name": "send", @@ -81,28 +81,28 @@ "qos": "", "retain": "", "broker": "2a15ab6f.ab2244", - "x": 730, - "y": 513, + "x": 710, + "y": 520, "wires": [] }, { - "id": "4f97d75.6c87528", + "id": "113ef524.57edeb", "type": "json", "z": "449c1517.e25f4c", "name": "Convert", "property": "payload", "action": "", "pretty": false, - "x": 260, - "y": 120, + "x": 240, + "y": 127, "wires": [ [ - "9f4b8dd3.2f0d2" + "120561a.088359e" ] ] }, { - "id": "9f4b8dd3.2f0d2", + "id": "120561a.088359e", "type": "switch", "z": "449c1517.e25f4c", "name": "Timeport", @@ -118,97 +118,97 @@ "checkall": "true", "repair": false, "outputs": 1, - "x": 420, - "y": 120, + "x": 400, + "y": 127, "wires": [ [ - "8ed813a9.a9319" + "d6f27e8e.93242" ] ] }, { - "id": "dac8aafa.389298", + "id": "90e76b02.6298f8", "type": "json", "z": "449c1517.e25f4c", "name": "Convert", "property": "payload", "action": "", "pretty": false, - "x": 580, - "y": 513, + "x": 560, + "y": 520, "wires": [ [ - "72d5e7ee.d1eba8" + "1c9a7438.6e38ec" ] ] }, { - "id": "8ed813a9.a9319", + "id": "d6f27e8e.93242", "type": "base64", "z": "449c1517.e25f4c", "name": "Decode", "action": "", "property": "payload.payload_raw", - "x": 580, - "y": 120, + "x": 560, + "y": 127, "wires": [ [ - "831ab883.d6a238" + "b8bd33fd.61caa" ] ] }, { - "id": "84f1cda2.069e7", + "id": "53a85e2c.2728d", "type": "base64", "z": "449c1517.e25f4c", "name": "Encode", "action": "", "property": "payload.payload_raw", - "x": 420, - "y": 513, + "x": 400, + "y": 520, "wires": [ [ - "dac8aafa.389298" + "90e76b02.6298f8" ] ] }, { - "id": "6190967b.01f758", + "id": "15980d22.6f4663", "type": "comment", "z": "449c1517.e25f4c", - "name": "LoRaWAN Timeserver v1.2", + "name": "LoRaWAN Timeserver v1.21", "info": "PLEASE NOTE: There is a patent filed for the time sync algorithm used in the\ncode of this file. The shown implementation example is covered by the\nrepository's licencse, but you may not be eligible to deploy the applied\nalgorithm in applications without granted license by the patent holder.", - "x": 170, - "y": 40, + "x": 160, + "y": 47, "wires": [] }, { - "id": "831ab883.d6a238", + "id": "b8bd33fd.61caa", "type": "function", "z": "449c1517.e25f4c", "name": "Timeserver Logic", - "func": "/* LoRaWAN Timeserver\n\nconstruct 7 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1 sequence number (taken from node's time_sync_req)\n2 timezone in 15 minutes steps\n3..6 current second (from epoch time 1970)\n7 1/250ths fractions of current second\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(7);\nnew DataView(buf).setUint8(0, seqNo);\n// Timezone (in 15min steps)\nvar timezone = 8; // CET = UTC+2h\nnew DataView(buf).setUint8(1, timezone);\nnew DataView(buf).setUint32(2, seconds);\nnew DataView(buf).setUint8(6, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9;\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", + "func": "/* LoRaWAN Timeserver\n\nconstruct 7 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1 sequence number (taken from node's time_sync_req)\n2 timezone in 15 minutes steps\n3..6 current second (from epoch time 1970)\n7 1/250ths fractions of current second\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n msg.port = 9; // Paxcounter TIMEPORT\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(7);\nnew DataView(buf).setUint8(0, seqNo);\n// Timezone (in 15min steps)\nvar timezone = 8; // CET = UTC+2h\nnew DataView(buf).setUint8(1, timezone);\nnew DataView(buf).setUint32(2, seconds);\nnew DataView(buf).setUint8(6, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9; // Paxcounter TIMEPORT\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", "outputs": 5, "noerr": 0, - "x": 350, - "y": 320, + "x": 330, + "y": 327, "wires": [ [ - "37722d4b.08e3c2", - "a8a04c7a.c5fbd", - "a15454a9.fa0948" + "c9a83ac9.50fd18", + "6aeb3720.a89618", + "6ac55bbe.12ac54" ], [ - "46ce842a.614d5c" + "de908e66.b6fd3" ], [ - "a5dbb4ef.019168" + "d5a35bab.44cb18" ], [ - "1cb58e7f.221362" + "3a661f0a.c61b1" ], [ - "49e3c067.e782e" + "9b4f492d.fbfd18" ] ], "outputLabels": [ @@ -220,7 +220,7 @@ ] }, { - "id": "37722d4b.08e3c2", + "id": "c9a83ac9.50fd18", "type": "debug", "z": "449c1517.e25f4c", "name": "Timeserver Gw", @@ -229,13 +229,13 @@ "console": false, "tostatus": true, "complete": "payload", - "x": 700, - "y": 240, + "x": 680, + "y": 247, "wires": [], "icon": "node-red/bridge.png" }, { - "id": "8712a5ac.ed18e8", + "id": "247204ab.a9f83c", "type": "ui_text", "z": "449c1517.e25f4c", "group": "edb7cc8d.a3817", @@ -246,12 +246,12 @@ "label": "Last answer at:", "format": "{{msg.payload}}", "layout": "col-center", - "x": 810, - "y": 300, + "x": 790, + "y": 307, "wires": [] }, { - "id": "46ce842a.614d5c", + "id": "de908e66.b6fd3", "type": "ui_gauge", "z": "449c1517.e25f4c", "name": "Timeserver offset", @@ -272,12 +272,12 @@ ], "seg1": "", "seg2": "", - "x": 710, - "y": 380, + "x": 690, + "y": 387, "wires": [] }, { - "id": "a8a04c7a.c5fbd", + "id": "6aeb3720.a89618", "type": "ui_text", "z": "449c1517.e25f4c", "group": "edb7cc8d.a3817", @@ -288,28 +288,28 @@ "label": "Gateway", "format": "{{msg.payload}}", "layout": "col-center", - "x": 700, - "y": 340, + "x": 680, + "y": 347, "wires": [] }, { - "id": "a15454a9.fa0948", + "id": "6ac55bbe.12ac54", "type": "function", "z": "449c1517.e25f4c", "name": "Time", "func": "msg.payload = new Date().toLocaleString('en-GB', {timeZone: 'Europe/Berlin'});\nreturn msg;", "outputs": 1, "noerr": 0, - "x": 670, - "y": 300, + "x": 650, + "y": 307, "wires": [ [ - "8712a5ac.ed18e8" + "247204ab.a9f83c" ] ] }, { - "id": "a5dbb4ef.019168", + "id": "d5a35bab.44cb18", "type": "ui_text", "z": "449c1517.e25f4c", "group": "edb7cc8d.a3817", @@ -320,12 +320,12 @@ "label": "Device", "format": "{{msg.payload}}", "layout": "col-center", - "x": 700, - "y": 420, + "x": 680, + "y": 427, "wires": [] }, { - "id": "1cb58e7f.221362", + "id": "3a661f0a.c61b1", "type": "ui_text", "z": "449c1517.e25f4c", "group": "edb7cc8d.a3817", @@ -336,8 +336,8 @@ "label": "Sequence", "format": "{{}}", "layout": "col-center", - "x": 700, - "y": 460, + "x": 680, + "y": 467, "wires": [] }, { From 36d9b3dedbb20d6c9d0a842bdb5ada2b0ea554df Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 5 Oct 2019 13:12:58 +0200 Subject: [PATCH 56/92] curve plotter fixes --- include/display.h | 6 ++-- src/display.cpp | 87 +++++++++++++++++++++++++---------------------- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/include/display.h b/include/display.h index 591814ba..0e94b806 100644 --- a/include/display.h +++ b/include/display.h @@ -14,8 +14,10 @@ void dp_printf(uint16_t x, uint16_t y, uint8_t font, uint8_t inv, void dp_printqr(uint16_t offset_x, uint16_t offset_y, const char *Message); void oledfillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t bRender); -void oledScrollBufferLeft(uint8_t *buf, const uint16_t width, - const uint16_t height); +void oledScrollBufferHorizontal(uint8_t *buf, const uint16_t width, + const uint16_t height, bool left = true); +void oledScrollBufferVertical(uint8_t *buf, const uint16_t width, + const uint16_t height, int offset = 0); int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y, const uint8_t dot); void oledPlotCurve(uint16_t count, bool reset); diff --git a/src/display.cpp b/src/display.cpp index 3eb792c8..fba15368 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -409,24 +409,55 @@ int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y, return 0; } -void oledScrollBufferLeft(uint8_t *buf, const uint16_t width, - const uint16_t height) { +void oledScrollBufferHorizontal(uint8_t *buf, const uint16_t width, + const uint16_t height, bool left) { uint16_t col, page, idx; for (page = 0; page < height / 8; page++) { - for (col = 0; col < width - 1; col++) { - idx = page * width + col; - buf[idx] = buf[idx + 1]; + if (left) { // scroll left + for (col = 0; col < width - 1; col++) { + idx = page * width + col; + buf[idx] = buf[idx + 1]; + } + buf[idx + 1] = 0; + } else // scroll right + { + for (col = width - 1; col > 0; col--) { + idx = page * width + col; + buf[idx] = buf[idx - 1]; + } + buf[idx - 1] = 0; } - buf[idx + 1] = 0; + } +} + +void oledScrollBufferVertical(uint8_t *buf, const uint16_t width, + const uint16_t height, int offset) { + + uint64_t buf_col; + + if (!offset) + return; // nothing to do + + for (uint16_t col = 0; col < DISPLAY_WIDTH; col++) { + // convert column bytes from display buffer to uint64_t + buf_col = *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8]; + + if (offset > 0) // scroll up + buf_col >= abs(offset); + else // scroll down + buf_col <= offset; + + // write back uint64_t to uint8_t display buffer + *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8] = buf_col; } } void oledPlotCurve(uint16_t count, bool reset) { static uint16_t last_count = 0, col = 0, row = 0; - static int scalefactor = 1, oldsf = 1; + uint16_t v_scroll = 0; if ((last_count == count) && !reset) return; @@ -435,47 +466,23 @@ void oledPlotCurve(uint16_t count, bool reset) { if (col < DISPLAY_WIDTH - 1) // matrix not full -> increment column col++; else // matrix full -> scroll left 1 dot - oledScrollBufferLeft(displaybuf, DISPLAY_WIDTH, DISPLAY_HEIGHT); + oledScrollBufferHorizontal(displaybuf, DISPLAY_WIDTH, DISPLAY_HEIGHT, + true); } else // clear current dot oledDrawPixel(displaybuf, col, row, 0); - // re-scale, if necessary - oldsf = scalefactor; - while (((count / scalefactor) <= DISPLAY_HEIGHT) && (scalefactor > 1)) - scalefactor--; - while ((count / scalefactor) > DISPLAY_HEIGHT) - scalefactor++; - if (scalefactor != oldsf) - oledRescaleBuffer(displaybuf, scalefactor); + // scroll up vertical, if necessary + while ((count - v_scroll) > DISPLAY_HEIGHT - 1) + v_scroll++; + if (v_scroll) + oledScrollBufferVertical(displaybuf, DISPLAY_WIDTH, DISPLAY_HEIGHT, + v_scroll); // set new dot - row = DISPLAY_HEIGHT - 1 - (count / scalefactor) % DISPLAY_HEIGHT; + row = DISPLAY_HEIGHT - 1 - (count - v_scroll) % DISPLAY_HEIGHT; last_count = count; oledDrawPixel(displaybuf, col, row, 1); } -void oledRescaleBuffer(uint8_t *buf, const int factor) { - - if (!factor) - return; - - uint64_t buf_col; - - for (uint16_t col = 0; col < DISPLAY_WIDTH; col++) { - // convert column bytes from display buffer to uint64_t - buf_col = *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8]; - - if (factor < 0) - // shift left: scroll up = scale down - buf_col <= abs(factor); - else - // shift right: scroll down = scale up - buf_col >= abs(factor); - - // write back uint64_t to uint8_t display buffer - *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8] = buf_col; - } -} - #endif // HAS_DISPLAY \ No newline at end of file From 06fb69d30467df4e99cfd0c92900f226e574d34f Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 5 Oct 2019 13:15:45 +0200 Subject: [PATCH 57/92] timesync.cpp cleanups --- src/timesync.cpp | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/timesync.cpp b/src/timesync.cpp index a50d7ca1..e0c0dbb3 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -94,7 +94,7 @@ void process_timesync_req(void *taskparameter) { // wrap around seqNo, keeping it in time port range time_sync_seqNo++; - if(time_sync_seqNo > TIMEREQUEST_MAX_SEQNO) { + if (time_sync_seqNo > TIMEREQUEST_MAX_SEQNO) { time_sync_seqNo = 0; } @@ -154,18 +154,30 @@ void store_time_sync_req(uint32_t timestamp) { timestamp % 1000); } -// process timeserver timestamp answer, called from lorawan.cpp +// process timeserver timestamp answer, called by myRxCallback() in lorawan.cpp int recv_timesync_ans(const uint8_t buf[], const uint8_t buf_len) { - uint8_t seq_no = buf[0]; - buf++; + + /* + parse 7 byte timesync_answer: + + byte meaning + 1 sequence number (taken from node's time_sync_req) + 2 timezone in 15 minutes steps + 3..6 current second (from epoch time 1970) + 7 1/250ths fractions of current second + */ // if no timesync handshake is pending then exit if (!timeSyncPending) return 0; // failure + // extract 1 byte timerequest sequence number from buffer + uint8_t seq_no = buf[0]; + buf++; + // if no time is available or spurious buffer then exit if (buf_len != TIME_SYNC_FRAME_LENGTH) { - if (buf[0] == 0xff) + if (seq_no == 0xff) ESP_LOGI(TAG, "[%0.3f] Timeserver error: no confident time available", millis() / 1000.0); else @@ -178,24 +190,26 @@ int recv_timesync_ans(const uint8_t buf[], const uint8_t buf_len) { uint8_t k = seq_no % TIME_SYNC_SAMPLES; - // 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[6]; - // 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; - uint32_t timezone_sec; - // extract timezone from buffer (in 15min steps, one step being 15min * 60s = 900s) - timezone_sec = buf[0]*900; + // extract 1 byte timezone from buffer (one step being 15min * 60s = 900s) + uint32_t timezone_sec = buf[0] * 900; buf++; - // convert buffer to uint32_t, octet order is big endian + // extract 4 bytes timestamp from buffer + // and convert it to uint32_t, octet order is big endian timestamp_ptr = (uint32_t *)buf; // swap byte order from msb to lsb, note: this is platform dependent timestamp_sec = __builtin_bswap32(*timestamp_ptr); + buf += 4; + // extract 1 byte fractional seconds in 2^-8 second steps + // (= 1/250th sec), we convert this to ms + uint16_t timestamp_msec = 4 * buf[0]; // construct the timepoint when message was seen on gateway - time_sync_rx[k] += seconds(timestamp_sec+timezone_sec) + milliseconds(timestamp_msec); + time_sync_rx[k] += + seconds(timestamp_sec + timezone_sec) + milliseconds(timestamp_msec); // we guess timepoint is recent if it newer than code compile date if (timeIsValid(myClock::to_time_t(time_sync_rx[k]))) { From 3d0c6f3249c383c52d5d8dd404df77e642fa1239 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 5 Oct 2019 13:46:36 +0200 Subject: [PATCH 58/92] Timeserver.json missing SeqNo fixed --- src/Timeserver/Nodered-Timeserver.json | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index 6b0cb5ff..085b132d 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -153,7 +153,8 @@ "y": 127, "wires": [ [ - "b8bd33fd.61caa" + "b8bd33fd.61caa", + "cc245719.3c4cd8" ] ] }, @@ -187,7 +188,7 @@ "type": "function", "z": "449c1517.e25f4c", "name": "Timeserver Logic", - "func": "/* LoRaWAN Timeserver\n\nconstruct 7 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1 sequence number (taken from node's time_sync_req)\n2 timezone in 15 minutes steps\n3..6 current second (from epoch time 1970)\n7 1/250ths fractions of current second\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n msg.port = 9; // Paxcounter TIMEPORT\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(7);\nnew DataView(buf).setUint8(0, seqNo);\n// Timezone (in 15min steps)\nvar timezone = 8; // CET = UTC+2h\nnew DataView(buf).setUint8(1, timezone);\nnew DataView(buf).setUint32(2, seconds);\nnew DataView(buf).setUint8(6, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9; // Paxcounter TIMEPORT\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", + "func": "/* LoRaWAN Timeserver\n\nconstruct 7 byte timesync_answer from gateway timestamp and node's time_sync_req\n\nbyte meaning\n1 sequence number (taken from node's time_sync_req)\n2 timezone in 15 minutes steps\n3..6 current second (from epoch time 1970)\n7 1/250ths fractions of current second\n\n*/\n\nfunction timecompare(a, b) {\n \n const timeA = a.time;\n const timeB = b.time;\n\n let comparison = 0;\n if (timeA > timeB) {\n comparison = 1;\n } else if (timeA < timeB) {\n comparison = -1;\n }\n return comparison;\n}\n\nlet confidence = 2000; // max millisecond diff gateway time to server time\n\n// guess if we have received a valid time_sync_req command\nif (msg.payload.payload_raw.length != 1)\n return;\n\nvar deviceMsg = { payload: msg.payload.dev_id };\nvar seqNo = msg.payload.payload_raw[0];\nvar seqNoMsg = { payload: seqNo };\nvar gateway_list = msg.payload.metadata.gateways;\n\n// filter all gateway timestamps that have milliseconds part (which we assume have a \".\")\nvar gateways = gateway_list.filter(function (element) {\n return (element.time.includes(\".\"));\n});\n\nvar gateway_time = gateways.map(gw => {\n return {\n time: new Date(gw.time),\n eui: gw.gtw_id,\n }\n });\nvar server_time = new Date(msg.payload.metadata.time);\n\n// validate all gateway timestamps against lorawan server_time (which is assumed to be recent)\nvar gw_timestamps = gateway_time.filter(function (element) {\n return ((element.time > (server_time - confidence) && element.time <= server_time));\n});\n\n// if no timestamp left, we have no valid one and exit\nif (gw_timestamps.length === 0) {\n var notavailMsg = { payload: \"n/a\" };\n var notimeMsg = { payload: 0xff }; \n var buf2 = Buffer.alloc(1);\n msg.payload = new Buffer(buf2.fill(0xff));\n msg.port = 9; // Paxcounter TIMEPORT\n return [notavailMsg, notavailMsg, deviceMsg, seqNoMsg, msg];}\n\n// sort time array in ascending order to find most recent timestamp for time answer\ngw_timestamps.sort(timecompare);\n\nvar timestamp = gw_timestamps[0].time;\nvar eui = gw_timestamps[0].eui;\nvar offset = server_time - timestamp;\n\nvar seconds = Math.floor(timestamp/1000);\nvar fractions = (timestamp % 1000) / 4;\n\nlet buf = new ArrayBuffer(7);\nnew DataView(buf).setUint8(0, seqNo);\n// Timezone (in 15min steps)\nvar timezone = 8; // CET = UTC+2h\nnew DataView(buf).setUint8(1, timezone);\nnew DataView(buf).setUint32(2, seconds);\nnew DataView(buf).setUint8(6, fractions);\n\nmsg.payload = new Buffer(new Uint8Array(buf));\nmsg.port = 9; // Paxcounter TIMEPORT\nvar euiMsg = { payload: eui };\nvar offsetMsg = { payload: offset };\n\nreturn [euiMsg, offsetMsg, deviceMsg, seqNoMsg, msg];", "outputs": 5, "noerr": 0, "x": 330, @@ -334,12 +335,26 @@ "height": 0, "name": "Sequence No", "label": "Sequence", - "format": "{{}}", + "format": "{{msg.payload}}", "layout": "col-center", "x": 680, "y": 467, "wires": [] }, + { + "id": "cc245719.3c4cd8", + "type": "debug", + "z": "449c1517.e25f4c", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "x": 860, + "y": 140, + "wires": [] + }, { "id": "2a15ab6f.ab2244", "type": "mqtt-broker", From 01fb7c53b4e44719bfd95a896ddcb5c62f347451 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 5 Oct 2019 15:03:15 +0200 Subject: [PATCH 59/92] randomize time sync seq nr --- include/timesync.h | 1 + src/paxcounter.conf | 3 +-- src/timesync.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/timesync.h b/include/timesync.h index 8b8c42bc..bf74700e 100644 --- a/include/timesync.h +++ b/include/timesync.h @@ -9,6 +9,7 @@ //#define TIME_SYNC_TRIGGER 100 // threshold for time sync [milliseconds] #define TIME_SYNC_FRAME_LENGTH 0x07 // timeserver answer frame length [bytes] #define TIME_SYNC_FIXUP 4 // calibration to fixup processing time [milliseconds] +#define TIMEREQUEST_MAX_SEQNO 0xf0 // threshold for wrap around seqno void timesync_init(void); void send_timesync_req(void); diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 02a53508..1ba4db3e 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -16,7 +16,7 @@ // Set this to include BLE counting and vendor filter functions, or to switch off WIFI counting #define VENDORFILTER 1 // set to 0 if you want to count things, not people -#define BLECOUNTER 1 // set it to 1 if you want to use BLE count, at expense of power & memory +#define BLECOUNTER 0 // set it to 1 if you want to use BLE count, at expense of power & memory #define WIFICOUNTER 1 // set it to 0 if you want to switch off WIFI count // BLE scan parameters @@ -99,7 +99,6 @@ #define BATTPORT 8 // battery voltage #define TIMEPORT 9 // time query and response #define TIMEDIFFPORT 13 // time adjust diff -#define TIMEREQUEST_MAX_SEQNO 250 // time answer, start of port range #define SENSOR1PORT 10 // user sensor #1 #define SENSOR2PORT 11 // user sensor #2 #define SENSOR3PORT 12 // user sensor #3 diff --git a/src/timesync.cpp b/src/timesync.cpp index e0c0dbb3..e77897cf 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -25,7 +25,7 @@ typedef std::chrono::duration> TaskHandle_t timeSyncReqTask = NULL; -static uint8_t time_sync_seqNo = 0; +static uint8_t time_sync_seqNo = (uint8_t)random(TIMEREQUEST_MAX_SEQNO); static bool timeSyncPending = false; static myClock_timepoint time_sync_tx[TIME_SYNC_SAMPLES]; static myClock_timepoint time_sync_rx[TIME_SYNC_SAMPLES]; From 7762170fa1a00b8dad301cd5fb44db701a437b3f Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 5 Oct 2019 23:08:13 +0200 Subject: [PATCH 60/92] fix JOIN WAIT problem with TTN --- src/lorawan.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index e6aa7114..21cf470c 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -484,6 +484,14 @@ void lmictask(void *pvParameters) { os_init(); // initialize lmic run-time environment LMIC_reset(); // initialize lmic MAC + +// Note that The Things Network uses the non-standard SF9BW125 data rate for RX2 +// in Europe and switches between RX1 and RX2 based on network congestion. Thus, +// to avoid occasionally join failures, we set datarate to SF9 and bypass the +// LORAWAN spec-compliant RX2 == SF12 setting +#if defined(CFG_eu868) + LMIC_setDrTxpow(EU868_DR_SF9, KEEP_TXPOW); +#endif LMIC_setLinkCheckMode(0); // This tells LMIC to make the receive windows bigger, in case your clock is @@ -645,7 +653,7 @@ uint8_t getBattLevel() { // u1_t os_getBattLevel(void) { return getBattLevel(); }; const char *getSfName(rps_t rps) { - const char *const t[] = {"FSK", "SF7", "SF8", "SF9", + const char *const t[] = {"FSK", "SF7", "SF8", "SF9", "SF10", "SF11", "SF12", "SF?"}; return t[getSf(rps)]; } From bdd401c42bae13831bdb270e8795e70fe0b736eb Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 6 Oct 2019 13:13:57 +0200 Subject: [PATCH 61/92] lorawan.cpp: TTN SF9 RX2 patch --- src/lorawan.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 21cf470c..942455d6 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -485,13 +485,19 @@ void lmictask(void *pvParameters) { os_init(); // initialize lmic run-time environment LMIC_reset(); // initialize lmic MAC -// Note that The Things Network uses the non-standard SF9BW125 data rate for RX2 -// in Europe and switches between RX1 and RX2 based on network congestion. Thus, -// to avoid occasionally join failures, we set datarate to SF9 and bypass the -// LORAWAN spec-compliant RX2 == SF12 setting #if defined(CFG_eu868) + // Note that The Things Network uses the non-standard SF9BW125 data rate for + // RX2 in Europe and switches between RX1 and RX2 based on network congestion. + // Thus, to avoid occasionally join failures, we set datarate to SF9 and + // bypass the LORAWAN spec-compliant RX2 == SF12 setting LMIC_setDrTxpow(EU868_DR_SF9, KEEP_TXPOW); +#else + // 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); #endif + LMIC_setLinkCheckMode(0); // This tells LMIC to make the receive windows bigger, in case your clock is @@ -511,11 +517,6 @@ 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); From f3ebb835af8a60bac8d607a9fbbd958134f5e71b Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 6 Oct 2019 13:14:23 +0200 Subject: [PATCH 62/92] curve plotter fixes --- src/display.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index fba15368..ef4e7529 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -117,10 +117,8 @@ void init_display(uint8_t verbose) { // display DEVEUI as plain text on the right dp_printf(72, 0, FONT_NORMAL, 0, "LORAWAN"); dp_printf(72, 1, FONT_NORMAL, 0, "DEVEUI:"); - dp_printf(80, 3, FONT_NORMAL, 0, "%4.4s", deveui); - dp_printf(80, 4, FONT_NORMAL, 0, "%4.4s", deveui + 4); - dp_printf(80, 5, FONT_NORMAL, 0, "%4.4s", deveui + 8); - dp_printf(80, 6, FONT_NORMAL, 0, "%4.4s", deveui + 12); + for (uint8_t i = 0; i <= 3; i++) + dp_printf(80, i + 3, FONT_NORMAL, 0, "%4.4s", deveui + i * 4); // give user some time to read or take picture oledDumpBuffer(NULL); @@ -444,10 +442,10 @@ void oledScrollBufferVertical(uint8_t *buf, const uint16_t width, // convert column bytes from display buffer to uint64_t buf_col = *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8]; - if (offset > 0) // scroll up - buf_col >= abs(offset); - else // scroll down - buf_col <= offset; + if (offset > 0) // scroll down + buf_col <= abs(offset); + else // scroll up + buf_col >= offset; // write back uint64_t to uint8_t display buffer *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8] = buf_col; @@ -472,7 +470,7 @@ void oledPlotCurve(uint16_t count, bool reset) { } else // clear current dot oledDrawPixel(displaybuf, col, row, 0); - // scroll up vertical, if necessary + // scroll down, if necessary while ((count - v_scroll) > DISPLAY_HEIGHT - 1) v_scroll++; if (v_scroll) @@ -480,7 +478,8 @@ void oledPlotCurve(uint16_t count, bool reset) { v_scroll); // set new dot - row = DISPLAY_HEIGHT - 1 - (count - v_scroll) % DISPLAY_HEIGHT; + //row = DISPLAY_HEIGHT - 1 - (count - v_scroll) % DISPLAY_HEIGHT; + row = DISPLAY_HEIGHT - 1 - count - v_scroll; last_count = count; oledDrawPixel(displaybuf, col, row, 1); } From 3e9fe65b2c44e28cb6544b05de06fcfb4e31b7d2 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 6 Oct 2019 14:25:29 +0200 Subject: [PATCH 63/92] display blanker added --- src/display.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index ef4e7529..bf3521d3 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -37,7 +37,7 @@ FONT_STRETCHED: 16x32px = 8 chars / line // local Tag for logging static const char TAG[] = __FILE__; -#define DISPLAY_PAGES (5) // number of paxcounter display pages +#define DISPLAY_PAGES (6) // number of paxcounter display pages // settings for oled display library #define USE_BACKBUFFER @@ -191,6 +191,7 @@ void draw_page(time_t t, uint8_t page) { // page 2: GPS // page 3: BME280/680 // page 4: time + // page 5: blank screen // page 0: parameters overview case 0: @@ -325,6 +326,12 @@ void draw_page(time_t t, uint8_t page) { second(t)); break; + // page 5: blank screen + case 5: + + oledFill(0, 1); + break; + default: break; // default @@ -478,7 +485,7 @@ void oledPlotCurve(uint16_t count, bool reset) { v_scroll); // set new dot - //row = DISPLAY_HEIGHT - 1 - (count - v_scroll) % DISPLAY_HEIGHT; + // row = DISPLAY_HEIGHT - 1 - (count - v_scroll) % DISPLAY_HEIGHT; row = DISPLAY_HEIGHT - 1 - count - v_scroll; last_count = count; oledDrawPixel(displaybuf, col, row, 1); From 27b3e88c3c1673795c2b01365d70149c1132dc8f Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 6 Oct 2019 14:25:49 +0200 Subject: [PATCH 64/92] v1.9.30 --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 1df56f70..6bc76104 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,7 +43,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 = 1.8.52 +release_version = 1.9.30 ; 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 @@ -51,7 +51,7 @@ extra_scripts = pre:build.py otakeyfile = ota.conf lorakeyfile = loraconf.h lmicconfigfile = lmic_config.h -platform_espressif32 = espressif32@1.9.0 +platform_espressif32 = espressif32@1.11.0 monitor_speed = 115200 upload_speed = 115200 lib_deps_lora = From c58971a2c62b09e448d82a87e03fe7befac3063c Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 6 Oct 2019 18:48:46 +0200 Subject: [PATCH 65/92] LMIC timings changed to avoid JOIN WAIT issue --- src/lmic_config.h | 4 ++-- src/lorawan.cpp | 16 ++-------------- src/paxcounter.conf | 4 ++-- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/lmic_config.h b/src/lmic_config.h index 788a07e1..3ed13904 100644 --- a/src/lmic_config.h +++ b/src/lmic_config.h @@ -18,7 +18,7 @@ // 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 +//#define LMIC_USE_INTERRUPTS 1 // time sync via LoRaWAN network, note: not supported by TTNv2 // #define LMIC_ENABLE_DeviceTimeReq 1 @@ -28,7 +28,7 @@ // so consuming more power. You may sharpen (reduce) this value if you are // limited on battery. // ATTN: VALUES > 7 WILL CAUSE RECEPTION AND JOIN PROBLEMS WITH HIGH SF RATES -//#define CLOCK_ERROR_PROCENTAGE 7 +#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 diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 942455d6..ce24cbc1 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -485,19 +485,8 @@ void lmictask(void *pvParameters) { os_init(); // initialize lmic run-time environment LMIC_reset(); // initialize lmic MAC -#if defined(CFG_eu868) - // Note that The Things Network uses the non-standard SF9BW125 data rate for - // RX2 in Europe and switches between RX1 and RX2 based on network congestion. - // Thus, to avoid occasionally join failures, we set datarate to SF9 and - // bypass the LORAWAN spec-compliant RX2 == SF12 setting - LMIC_setDrTxpow(EU868_DR_SF9, KEEP_TXPOW); -#else - // 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); -#endif - + // pre-join settings + LMIC_setDrTxpow(assertDR(LORADRDEFAULT), LORATXPOWDEFAULT); LMIC_setLinkCheckMode(0); // This tells LMIC to make the receive windows bigger, in case your clock is @@ -508,7 +497,6 @@ void lmictask(void *pvParameters) { 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 diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 1ba4db3e..1f3dc167 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -47,8 +47,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 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 LORADRDEFAULT 3 // 0 .. 15, LoRaWAN datarate, according to regional LoRaWAN specs [use 3 for TTN in EU] +#define LORATXPOWDEFAULT 14 // 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] From d57c48a97fa64276aef10aa3c8b1b81d602342dc Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 6 Oct 2019 19:05:38 +0200 Subject: [PATCH 66/92] bugfix rcommand set_loradr(): keep TX Power --- src/rcommand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcommand.cpp b/src/rcommand.cpp index e8b9f3da..4290555c 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -191,7 +191,7 @@ void set_loradr(uint8_t val[]) { 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); + LMIC_setDrTxpow(assertDR(cfg.loradr), KEEP_TXPOW); ESP_LOGI(TAG, "Radio parameters now %s / %s / %s", getSfName(updr2rps(LMIC.datarate)), getBwName(updr2rps(LMIC.datarate)), From 88e73e2eb8263319328b92819893339534eda29e Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Wed, 9 Oct 2019 20:07:16 +0200 Subject: [PATCH 67/92] Lora network setup + event handler elaborated --- include/lorawan.h | 3 +- src/configmanager.cpp | 2 +- src/lorawan.cpp | 286 +++++++++++++++++++++++------------------- 3 files changed, 157 insertions(+), 134 deletions(-) diff --git a/include/lorawan.h b/include/lorawan.h index a69aa4ba..6d1543d9 100644 --- a/include/lorawan.h +++ b/include/lorawan.h @@ -31,8 +31,8 @@ typedef struct { } mac_t; esp_err_t lora_stack_init(); +void lora_setupForNetwork(bool preJoin); void lmictask(void *pvParameters); -void onEvent(ev_t ev); void gen_lora_deveui(uint8_t *pdeveui); void RevBytes(unsigned char *b, size_t c); void get_hard_deveui(uint8_t *pdeveui); @@ -43,6 +43,7 @@ void showLoraKeys(void); void lora_send(void *pvParameters); void lora_enqueuedata(MessageBuffer_t *message); void lora_queuereset(void); +void myEventCallback(void *pUserData, ev_t ev); void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg, size_t nMsg); void myTxCallback(void *pUserData, int fSuccess); diff --git a/src/configmanager.cpp b/src/configmanager.cpp index c629d617..41e196e6 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -15,7 +15,7 @@ esp_err_t err; // populate cfg vars with factory settings void defaultConfig() { - cfg.loradr = LORADRDEFAULT; // 0-15, lora datarate, see pacounter.conf + cfg.loradr = LORADRDEFAULT; // 0-15, lora datarate, see paxcounter.conf cfg.txpower = LORATXPOWDEFAULT; // 0-15, lora tx power cfg.adrmode = 1; // 0=disabled, 1=enabled cfg.screensaver = 0; // 0=disabled, 1=enabled diff --git a/src/lorawan.cpp b/src/lorawan.cpp index ce24cbc1..3803fb04 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -75,6 +75,39 @@ const lmic_pinmap lmic_pins = { .spi_freq = 0, .pConfig = &myHalConfig}; +void lora_setupForNetwork(bool preJoin) { + + if (preJoin) { + +#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, this will need to be changed. + LMIC_selectSubBand(1); +#elif CFG_LMIC_EU_like + // setting for TheThingsNetwork + // TTN uses SF9, not SF12, for RX2 window + LMIC.dn2Dr = EU868_DR_SF9; + // Disable link check validation + LMIC_setLinkCheckMode(0); +#endif + + } else { + // set data rate adaptation according to saved setting + LMIC_setAdrMode(cfg.adrmode); + // set data rate and transmit power to stored device values if 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))); + } +} + // DevEUI generator using devices's MAC address void gen_lora_deveui(uint8_t *pdeveui) { uint8_t *p = pdeveui, dmac[6]; @@ -204,117 +237,6 @@ void showLoraKeys(void) { #endif // VERBOSE -void onEvent(ev_t ev) { - char buff[24] = ""; - - switch (ev) { - - case EV_SCAN_TIMEOUT: - strcpy_P(buff, PSTR("SCAN TIMEOUT")); - break; - - case EV_BEACON_FOUND: - strcpy_P(buff, PSTR("BEACON FOUND")); - break; - - case EV_BEACON_MISSED: - strcpy_P(buff, PSTR("BEACON MISSED")); - break; - - case EV_BEACON_TRACKED: - strcpy_P(buff, PSTR("BEACON TRACKED")); - break; - - case EV_JOINING: - strcpy_P(buff, PSTR("JOINING")); - break; - - case EV_JOINED: - strcpy_P(buff, PSTR("JOINED")); - // set data rate adaptation according to saved setting - LMIC_setAdrMode(cfg.adrmode); - // 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: - strcpy_P(buff, PSTR("RFU1")); - break; - - case EV_JOIN_FAILED: - strcpy_P(buff, PSTR("JOIN FAILED")); - break; - - case EV_REJOIN_FAILED: - strcpy_P(buff, PSTR("REJOIN FAILED")); - break; - - case EV_TXCOMPLETE: - strcpy_P(buff, PSTR("TX COMPLETE")); - break; - - case EV_LOST_TSYNC: - strcpy_P(buff, PSTR("LOST TSYNC")); - break; - - case EV_RESET: - strcpy_P(buff, PSTR("RESET")); - break; - - case EV_RXCOMPLETE: - // data received in ping slot - strcpy_P(buff, PSTR("RX COMPLETE")); - break; - - case EV_LINK_DEAD: - strcpy_P(buff, PSTR("LINK DEAD")); - break; - - case EV_LINK_ALIVE: - strcpy_P(buff, PSTR("LINK_ALIVE")); - break; - - case EV_SCAN_FOUND: - strcpy_P(buff, PSTR("SCAN FOUND")); - break; - - case EV_TXSTART: - if (!(LMIC.opmode & OP_JOINING)) { - strcpy_P(buff, PSTR("TX START")); - } - break; - - case EV_TXCANCELED: - strcpy_P(buff, PSTR("TX CANCELLED")); - break; - - case EV_RXSTART: - strcpy_P(buff, PSTR("RX START")); - break; - - case EV_JOIN_TXCOMPLETE: - strcpy_P(buff, PSTR("JOIN WAIT")); - break; - - default: - sprintf_P(buff, PSTR("LMIC EV %d"), ev); - break; - } - - // Log & Display if asked - if (*buff) { - ESP_LOGI(TAG, "%s", buff); - sprintf(lmic_event_msg, buff); - } -} - // LMIC send task void lora_send(void *pvParameters) { configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check @@ -351,7 +273,8 @@ void lora_send(void *pvParameters) { 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 + 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 @@ -385,9 +308,9 @@ esp_err_t lora_stack_init() { &lmicTask, // task handle 1); // CPU core - if (!LMIC_startJoining()) { // start joining + // start joining + if (!LMIC_startJoining()) ESP_LOGI(TAG, "Already joined"); - } // start lmic send task xTaskCreatePinnedToCore(lora_send, // task function @@ -480,34 +403,32 @@ finish: // LMIC lorawan stack task void lmictask(void *pvParameters) { - configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check + configASSERT(((uint32_t)pvParameters) == 1); - os_init(); // initialize lmic run-time environment - LMIC_reset(); // initialize lmic MAC + // setup LMIC stack + os_init(); // initialize lmic run-time environment + // os_init_ex(pPinMap); - // pre-join settings - LMIC_setDrTxpow(assertDR(LORADRDEFAULT), LORATXPOWDEFAULT); - LMIC_setLinkCheckMode(0); + // register a callback for downlink messages. We aren't trying to write + // reentrant code, so pUserData is NULL. LMIC_reset() doesn't affect + // callbacks, so we can do this first. + LMIC_registerRxMessageCb(myRxCallback, NULL); + LMIC_registerEventCb(myEventCallback, NULL); + + // Reset the MAC state. Session and pending data transfers will be + // discarded. + LMIC_reset(); // 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); + LMIC_setClockError(CLOCK_ERROR_PROCENTAGE * MAX_CLOCK_ERROR / 100); #endif -#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, - // this will need to be changed. - LMIC_selectSubBand(1); -#endif - - // register a callback for downlink messages. We aren't trying to write - // reentrant code, so pUserData is NULL. - LMIC_registerRxMessageCb(myRxCallback, NULL); + // do the network-specific setup prior to join. + lora_setupForNetwork(true); while (1) { os_runloop_once(); // execute lmic scheduled jobs and events @@ -515,6 +436,107 @@ void lmictask(void *pvParameters) { } } // lmictask +// lmic event handler +void myEventCallback(void *pUserData, ev_t ev) { + char buff[24] = ""; + + switch (ev) { + + case EV_SCAN_TIMEOUT: + strcpy_P(buff, PSTR("SCAN TIMEOUT")); + break; + + case EV_BEACON_FOUND: + strcpy_P(buff, PSTR("BEACON FOUND")); + break; + + case EV_BEACON_MISSED: + strcpy_P(buff, PSTR("BEACON MISSED")); + break; + + case EV_BEACON_TRACKED: + strcpy_P(buff, PSTR("BEACON TRACKED")); + break; + + case EV_JOINING: + strcpy_P(buff, PSTR("JOINING")); + break; + + case EV_JOINED: + strcpy_P(buff, PSTR("JOINED")); + lora_setupForNetwork(false); + break; + + case EV_RFU1: + strcpy_P(buff, PSTR("RFU1")); + break; + + case EV_JOIN_FAILED: + strcpy_P(buff, PSTR("JOIN FAILED")); + break; + + case EV_REJOIN_FAILED: + strcpy_P(buff, PSTR("REJOIN FAILED")); + break; + + case EV_TXCOMPLETE: + strcpy_P(buff, PSTR("TX COMPLETE")); + break; + + case EV_LOST_TSYNC: + strcpy_P(buff, PSTR("LOST TSYNC")); + break; + + case EV_RESET: + strcpy_P(buff, PSTR("RESET")); + break; + + case EV_RXCOMPLETE: + strcpy_P(buff, PSTR("RX COMPLETE")); + break; + + case EV_LINK_DEAD: + strcpy_P(buff, PSTR("LINK DEAD")); + break; + + case EV_LINK_ALIVE: + strcpy_P(buff, PSTR("LINK_ALIVE")); + break; + + case EV_SCAN_FOUND: + strcpy_P(buff, PSTR("SCAN FOUND")); + break; + + case EV_TXSTART: + if (!(LMIC.opmode & OP_JOINING)) { + strcpy_P(buff, PSTR("TX START")); + } + break; + + case EV_TXCANCELED: + strcpy_P(buff, PSTR("TX CANCELLED")); + break; + + case EV_RXSTART: + strcpy_P(buff, PSTR("RX START")); + break; + + case EV_JOIN_TXCOMPLETE: + strcpy_P(buff, PSTR("JOIN WAIT")); + break; + + default: + sprintf_P(buff, PSTR("LMIC EV %d"), ev); + break; + } + + // Log & Display if asked + if (*buff) { + ESP_LOGI(TAG, "%s", buff); + sprintf(lmic_event_msg, buff); + } +} + // receive message handler void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg, size_t nMsg) { From a52b4aa858b8e059e07c7634db8b75c337771b09 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Thu, 10 Oct 2019 10:29:10 +0200 Subject: [PATCH 68/92] lorawan network setup tuned (RX2==SF9 for TTN) --- src/lorawan.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 3803fb04..41ca8e16 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -246,9 +246,9 @@ void lora_send(void *pvParameters) { while (1) { // postpone until we are joined if we are not - while (!LMIC.devaddr) { - vTaskDelay(pdMS_TO_TICKS(500)); - } + // 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) { @@ -259,7 +259,8 @@ void lora_send(void *pvParameters) { // attempt to transmit payload else { - switch (LMIC_sendWithCallback_strict( + // switch (LMIC_sendWithCallback_strict( + switch (LMIC_sendWithCallback( SendBuffer.MessagePort, SendBuffer.Message, SendBuffer.MessageSize, (cfg.countermode & 0x02), myTxCallback, NULL)) { @@ -427,9 +428,6 @@ void lmictask(void *pvParameters) { LMIC_setClockError(CLOCK_ERROR_PROCENTAGE * MAX_CLOCK_ERROR / 100); #endif - // do the network-specific setup prior to join. - lora_setupForNetwork(true); - while (1) { os_runloop_once(); // execute lmic scheduled jobs and events delay(2); // yield to CPU @@ -460,10 +458,13 @@ void myEventCallback(void *pUserData, ev_t ev) { case EV_JOINING: strcpy_P(buff, PSTR("JOINING")); + // do the network-specific setup prior to join. + lora_setupForNetwork(true); break; case EV_JOINED: strcpy_P(buff, PSTR("JOINED")); + // do the after join network-specific setup. lora_setupForNetwork(false); break; @@ -508,9 +509,7 @@ void myEventCallback(void *pUserData, ev_t ev) { break; case EV_TXSTART: - if (!(LMIC.opmode & OP_JOINING)) { strcpy_P(buff, PSTR("TX START")); - } break; case EV_TXCANCELED: From 36c178054afdc8071854bd0eb75ad47b9fb51532 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Thu, 10 Oct 2019 11:06:24 +0200 Subject: [PATCH 69/92] lmic_config.h use interrupts --- src/lmic_config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lmic_config.h b/src/lmic_config.h index 3ed13904..e668bc70 100644 --- a/src/lmic_config.h +++ b/src/lmic_config.h @@ -18,7 +18,7 @@ // 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 +#define LMIC_USE_INTERRUPTS 1 // time sync via LoRaWAN network, note: not supported by TTNv2 // #define LMIC_ENABLE_DeviceTimeReq 1 @@ -28,14 +28,14 @@ // so consuming more power. You may sharpen (reduce) this value if you are // limited on battery. // ATTN: VALUES > 7 WILL CAUSE RECEPTION AND JOIN PROBLEMS WITH HIGH SF RATES -#define CLOCK_ERROR_PROCENTAGE 7 +//#define CLOCK_ERROR_PROCENTAGE 5 // Set this to 1 to enable some basic debug output (using printf) about // RF settings used during transmission and reception. Set to 2 to // enable more verbose output. Make sure that printf is actually // configured (e.g. on AVR it is not by default), otherwise using it can // cause crashing. -#define LMIC_DEBUG_LEVEL 0 +//#define LMIC_DEBUG_LEVEL 1 // Enable this to allow using printf() to print to the given serial port // (or any other Print object). This can be easy for debugging. The From 426ab6b2609298dae62ebf8d5d704e39a2e6694f Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Thu, 10 Oct 2019 14:55:51 +0200 Subject: [PATCH 70/92] lorawan.cpp code sanitizations --- src/lorawan.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 41ca8e16..31c5ae80 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -100,8 +100,8 @@ void lora_setupForNetwork(bool preJoin) { 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", + 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))); @@ -309,7 +309,7 @@ esp_err_t lora_stack_init() { &lmicTask, // task handle 1); // CPU core - // start joining + // start join if (!LMIC_startJoining()) ESP_LOGI(TAG, "Already joined"); @@ -408,11 +408,10 @@ void lmictask(void *pvParameters) { // setup LMIC stack os_init(); // initialize lmic run-time environment - // os_init_ex(pPinMap); - // register a callback for downlink messages. We aren't trying to write - // reentrant code, so pUserData is NULL. LMIC_reset() doesn't affect - // callbacks, so we can do this first. + // register a callback for downlink messages and lmic events. + // We aren't trying to write reentrant code, so pUserData is NULL. + // LMIC_reset() doesn't affect callbacks, so we can do this first. LMIC_registerRxMessageCb(myRxCallback, NULL); LMIC_registerEventCb(myEventCallback, NULL); @@ -509,7 +508,7 @@ void myEventCallback(void *pUserData, ev_t ev) { break; case EV_TXSTART: - strcpy_P(buff, PSTR("TX START")); + strcpy_P(buff, PSTR("TX START")); break; case EV_TXCANCELED: @@ -531,7 +530,7 @@ void myEventCallback(void *pUserData, ev_t ev) { // Log & Display if asked if (*buff) { - ESP_LOGI(TAG, "%s", buff); + ESP_LOGD(TAG, "%s", buff); sprintf(lmic_event_msg, buff); } } From fc7a8b361b467957c22e7b4fad5da2f8b821f935 Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Thu, 10 Oct 2019 17:34:01 +0200 Subject: [PATCH 71/92] development reverted to cyberman development --- build.py | 9 ++- include/macsniff.h | 1 - include/main.h | 3 +- include/payload.h | 1 - src/Timeserver/Nodered-Timeserver.json | 29 +++++---- src/lorawan.cpp | 2 +- src/macsniff.cpp | 32 +--------- src/main.cpp | 6 +- src/ota.sample.conf | 1 - src/payload.cpp | 15 ++--- src/timesync.cpp | 1 - src/uart.cpp | 83 -------------------------- src/uart.h | 15 ----- 13 files changed, 31 insertions(+), 167 deletions(-) delete mode 100644 src/uart.cpp delete mode 100644 src/uart.h diff --git a/build.py b/build.py index 685ada36..c4f3ccc3 100644 --- a/build.py +++ b/build.py @@ -98,11 +98,10 @@ env.Replace(BINTRAY_API_TOKEN=apitoken) # get runtime credentials and put them to compiler directive env.Append(BUILD_FLAGS=[ - u'-DWIFI_SSID=\\"' + mykeys["OTA_WIFI_SSID"] + '\\"', - u'-DWIFI_PASS=\\"' + mykeys["OTA_WIFI_PASS"] + '\\"', - u'-DOTA_TRIGGER_MAC=\\"' + mykeys["OTA_TRIGGER_MAC"] + '\\"', - u'-DBINTRAY_USER=\\"' + mykeys["BINTRAY_USER"] + '\\"', - u'-DBINTRAY_REPO=\\"' + mykeys["BINTRAY_REPO"] + '\\"', + u'-DWIFI_SSID=\\"' + mykeys["OTA_WIFI_SSID"] + '\\"', + u'-DWIFI_PASS=\\"' + mykeys["OTA_WIFI_PASS"] + '\\"', + u'-DBINTRAY_USER=\\"' + mykeys["BINTRAY_USER"] + '\\"', + u'-DBINTRAY_REPO=\\"' + mykeys["BINTRAY_REPO"] + '\\"', u'-DBINTRAY_PACKAGE=\\"' + package + '\\"', u'-DARDUINO_LMIC_PROJECT_CONFIG_H=' + lmicconfig, u'-I \"' + srcdir + '\"' diff --git a/include/macsniff.h b/include/macsniff.h index 663a7749..d41fc787 100644 --- a/include/macsniff.h +++ b/include/macsniff.h @@ -12,7 +12,6 @@ #define MAC_SNIFF_WIFI 0 #define MAC_SNIFF_BLE 1 -void macsniff_setup(void); uint16_t get_salt(void); uint64_t macConvert(uint8_t *paddr); bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type); diff --git a/include/main.h b/include/main.h index ebb1d440..4b5617cb 100644 --- a/include/main.h +++ b/include/main.h @@ -18,8 +18,7 @@ #include "irqhandler.h" #include "led.h" #include "spislave.h" -#include "uart.h" -#if(HAS_LORA) +#if (HAS_LORA) #include "lorawan.h" #endif #include "timekeeper.h" diff --git a/include/payload.h b/include/payload.h index 8ae86e6e..b41bb113 100644 --- a/include/payload.h +++ b/include/payload.h @@ -55,7 +55,6 @@ public: void addButton(uint8_t value); void addSensor(uint8_t[]); void addTime(time_t value); - void addTimeDiff(int32_t value); #if (PAYLOAD_ENCODER == 1) // format plain diff --git a/src/Timeserver/Nodered-Timeserver.json b/src/Timeserver/Nodered-Timeserver.json index 118161a1..085b132d 100644 --- a/src/Timeserver/Nodered-Timeserver.json +++ b/src/Timeserver/Nodered-Timeserver.json @@ -14,17 +14,26 @@ "to": "down", "tot": "str" }, - "page-titlebar-backgroundColor":{ - "value":"#0094CE", - "edited":false + { + "t": "set", + "p": "payload.confirmed", + "pt": "msg", + "to": "false", + "tot": "bool" }, - "page-backgroundColor":{ - "value":"#fafafa", - "edited":false + { + "t": "set", + "p": "payload.schedule", + "pt": "msg", + "to": "replace", + "tot": "str" }, - "page-sidebar-backgroundColor":{ - "value":"#ffffff", - "edited":false + { + "t": "move", + "p": "payload", + "pt": "msg", + "to": "payload.payload_raw", + "tot": "msg" }, { "t": "move", @@ -390,4 +399,4 @@ "disabled": false, "hidden": false } -] +] \ No newline at end of file diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 791725bd..31c5ae80 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -677,4 +677,4 @@ const char *getCrName(rps_t rps) { return t[getCr(rps)]; } -#endif // HAS_LORA +#endif // HAS_LORA \ No newline at end of file diff --git a/src/macsniff.cpp b/src/macsniff.cpp index 079c2f8c..0b00e7c1 100644 --- a/src/macsniff.cpp +++ b/src/macsniff.cpp @@ -6,21 +6,10 @@ #include "vendor_array.h" #endif -#include -#include - // Local logging tag static const char TAG[] = __FILE__; uint16_t salt; -uint64_t fota_trigger_mac; - -void macsniff_setup() { - std::stringstream ss; - ss << std::hex << OTA_TRIGGER_MAC; - ss >> fota_trigger_mac; - std::cout << static_cast(fota_trigger_mac) << std::endl; -} uint16_t get_salt(void) { salt = (uint16_t)random(65536); // get new 16bit random for salting hashes @@ -93,25 +82,6 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { // Count only if MAC was not yet seen if (added) { - ESP_LOGD(TAG, "new Mac: %x:%x:%x:%x:%x:%x", - paddr[0], - paddr[1], - paddr[2], - paddr[3], - paddr[4], - paddr[5] - ); - // is newly found MAC the OTA trigger? - uint64_t addr48 = (((uint64_t)paddr[3]) | ((uint64_t)paddr[2] << 8) | - ((uint64_t)paddr[1] << 16) | ((uint64_t)paddr[0] << 24)); - if((int)(addr48-fota_trigger_mac) == 0) - { - ESP_LOGI(TAG, "OTA-MAC found, Update triggered"); - // initiate OTA update - uint8_t cmd[2] = {9, 9}; - rcommand(cmd, 2); - } - // increment counter and one blink led if (sniff_type == MAC_SNIFF_WIFI) { macs_wifi++; // increment Wifi MACs counter @@ -164,4 +134,4 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { // True if MAC WiFi/BLE was new return added; // function returns bool if a new and unique Wifi or BLE mac was // counted (true) or not (false) -} +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 602a8e8a..79b692ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -465,11 +465,7 @@ void setup() { // show compiled features ESP_LOGI(TAG, "Features:%s", features); - macsniff_setup(); - - uart_setup(); - -} // setup() + vTaskDelete(NULL); } // setup() diff --git a/src/ota.sample.conf b/src/ota.sample.conf index fa698c31..a10d79dc 100644 --- a/src/ota.sample.conf +++ b/src/ota.sample.conf @@ -1,7 +1,6 @@ [ota] OTA_WIFI_SSID = MyHomeWifi OTA_WIFI_PASS = FooBar42! -OTA_TRIGGER_MAC = FFFFFFFF [bintray] BINTRAY_USER = MyBintrayUser diff --git a/src/payload.cpp b/src/payload.cpp index e755f077..fad4a1bc 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -16,14 +16,7 @@ uint8_t *PayloadConvert::getBuffer(void) { return buffer; } /* ---------------- plain format without special encoding ---------- */ -void PayloadConvert::addTimeDiff(int32_t value) { - buffer[cursor++] = (byte)((value & 0xFF000000) >> 24); - buffer[cursor++] = (byte)((value & 0x00FF0000) >> 16); - buffer[cursor++] = (byte)((value & 0x0000FF00) >> 8); - buffer[cursor++] = (byte)((value & 0x000000FF)); -} - -#if PAYLOAD_ENCODER == 1 +#if (PAYLOAD_ENCODER == 1) void PayloadConvert::addByte(uint8_t value) { buffer[cursor++] = (value); } @@ -315,8 +308,8 @@ void PayloadConvert::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, #elif ((PAYLOAD_ENCODER == 3) || (PAYLOAD_ENCODER == 4)) -void PayloadConvert::addByte(uint8_t value) { - /* +void PayloadConvert::addByte(uint8_t value) { + /* not implemented */ } @@ -493,4 +486,4 @@ void PayloadConvert::addTime(time_t value) { #endif } -#endif +#endif \ No newline at end of file diff --git a/src/timesync.cpp b/src/timesync.cpp index 5b1b4d34..e77897cf 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -12,7 +12,6 @@ algorithm in applications without granted license by the patent holder. #if (TIME_SYNC_LORASERVER) && (HAS_LORA) #include "timesync.h" -#include "uart.h" // Local logging tag static const char TAG[] = __FILE__; diff --git a/src/uart.cpp b/src/uart.cpp deleted file mode 100644 index b71b3e28..00000000 --- a/src/uart.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "rtctime.h" - -#include -#include - -#include -#include "globals.h" -#include "uart.h" -#include "driver/uart.h" - -static const char TAG[] = __FILE__; -TaskHandle_t UartTask = NULL; - -void uart_setup() { - // setup UART connection - uart_config_t uart_config = { - .baud_rate = 9600, - .data_bits = UART_DATA_7_BITS, - .parity = UART_PARITY_EVEN, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE - }; - uart_param_config(UART_NUM_1, &uart_config); - uart_set_pin(UART_NUM_1, CLOCK_DCF_TXD, CLOCK_DCF_RXD, CLOCK_DCF_RTS, CLOCK_DCF_CTS); - uart_driver_install(UART_NUM_1, CLOCK_BUF_SIZE * 2, 0, 0, NULL, 0); -} - -void time_uart_send(void * pvParameters) { - struct timeval curTime; - - const char* format = "\bOAL%y%m%dF%H%M%S\r"; - char timestamp[64] = {0}; - TickType_t xLastWakeTime = xTaskGetTickCount(); - - for(;;) { - struct timeval tv; - struct timezone tz; - if(gettimeofday(&tv, &tz) != 0) { - ESP_LOGI(TAG, "ERROR gettimeofday"); - } - time_t nowTime = tv.tv_sec; - strftime(timestamp, sizeof(timestamp), format, localtime(&nowTime)); - ESP_LOGI(TAG, "Current Time: %s", timestamp); - - int len = strlen(timestamp)+1; - - // Send Data via UART - uart_write_bytes(UART_NUM_1, timestamp, len); - - // gettimeofday(&curTime, &tz); - int sleep = 1000 - (curTime.tv_usec/1000); - ostime_t now = os_getTime(); - ESP_LOGD(TAG, "Sleep Time: %d, now: %d\n", sleep, now); - vTaskDelayUntil( &xLastWakeTime, (TickType_t)(sleep/portTICK_PERIOD_MS) ); - - // Read UART for testing purposes - /** - uint8_t *data = (uint8_t *) malloc(CLOCK_BUF_SIZE); - - // Read Data via UART - uart_read_bytes(UART_NUM_1, data, CLOCK_BUF_SIZE, 20 / portTICK_RATE_MS); - const char * dataC = (const char *) data; - ESP_LOGI(TAG, "Data Read: %s", dataC); - - free(data); - **/ - } - - vTaskDelete(NULL); -} - -void time_uart_send_start() { - if (UartTask) { - return; - } - xTaskCreatePinnedToCore(time_uart_send, // task function - "time_uart_send", // name of task - 2048, // stack size of task - (void *)1, // parameter of the task - 2, // priority of the task - &UartTask, // task handle - 1); // CPU core -} diff --git a/src/uart.h b/src/uart.h deleted file mode 100644 index f12acbaf..00000000 --- a/src/uart.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef UART_H -#define UART_H - -// UART for Clock DCF -#define CLOCK_DCF_TXD (GPIO_NUM_4) -#define CLOCK_DCF_RXD (GPIO_NUM_15) -#define CLOCK_DCF_RTS (UART_PIN_NO_CHANGE) -#define CLOCK_DCF_CTS (UART_PIN_NO_CHANGE) -#define CLOCK_BUF_SIZE (1024) - -void time_uart_send(void * pvParameters); -void time_uart_send_start(); -void uart_setup(); - -#endif From f417e336a2efbb2302076c349ed1a2435254f4ff Mon Sep 17 00:00:00 2001 From: Marius Gripp Date: Thu, 10 Oct 2019 16:11:38 +0200 Subject: [PATCH 72/92] issue 464 fix: time set in UTC --- src/timesync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timesync.cpp b/src/timesync.cpp index e77897cf..917140d0 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -209,7 +209,7 @@ int recv_timesync_ans(const uint8_t buf[], const uint8_t buf_len) { // construct the timepoint when message was seen on gateway time_sync_rx[k] += - seconds(timestamp_sec + timezone_sec) + milliseconds(timestamp_msec); + seconds(timestamp_sec) + milliseconds(timestamp_msec); // we guess timepoint is recent if it newer than code compile date if (timeIsValid(myClock::to_time_t(time_sync_rx[k]))) { From 025411267b75d009f8266f3ad74a58dafe1f0236 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Thu, 10 Oct 2019 22:46:49 +0200 Subject: [PATCH 73/92] lora event handler refactored --- src/lorawan.cpp | 95 ++++++------------------------------------------- 1 file changed, 10 insertions(+), 85 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 31c5ae80..32e102f7 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -435,104 +435,29 @@ void lmictask(void *pvParameters) { // lmic event handler void myEventCallback(void *pUserData, ev_t ev) { - char buff[24] = ""; + + static const char *const evNames[] = {LMIC_EVENT_NAME_TABLE__INIT}; switch (ev) { - - case EV_SCAN_TIMEOUT: - strcpy_P(buff, PSTR("SCAN TIMEOUT")); - break; - - case EV_BEACON_FOUND: - strcpy_P(buff, PSTR("BEACON FOUND")); - break; - - case EV_BEACON_MISSED: - strcpy_P(buff, PSTR("BEACON MISSED")); - break; - - case EV_BEACON_TRACKED: - strcpy_P(buff, PSTR("BEACON TRACKED")); - break; - case EV_JOINING: - strcpy_P(buff, PSTR("JOINING")); // do the network-specific setup prior to join. lora_setupForNetwork(true); break; case EV_JOINED: - strcpy_P(buff, PSTR("JOINED")); // do the after join network-specific setup. lora_setupForNetwork(false); break; - - case EV_RFU1: - strcpy_P(buff, PSTR("RFU1")); - break; - - case EV_JOIN_FAILED: - strcpy_P(buff, PSTR("JOIN FAILED")); - break; - - case EV_REJOIN_FAILED: - strcpy_P(buff, PSTR("REJOIN FAILED")); - break; - - case EV_TXCOMPLETE: - strcpy_P(buff, PSTR("TX COMPLETE")); - break; - - case EV_LOST_TSYNC: - strcpy_P(buff, PSTR("LOST TSYNC")); - break; - - case EV_RESET: - strcpy_P(buff, PSTR("RESET")); - break; - - case EV_RXCOMPLETE: - strcpy_P(buff, PSTR("RX COMPLETE")); - break; - - case EV_LINK_DEAD: - strcpy_P(buff, PSTR("LINK DEAD")); - break; - - case EV_LINK_ALIVE: - strcpy_P(buff, PSTR("LINK_ALIVE")); - break; - - case EV_SCAN_FOUND: - strcpy_P(buff, PSTR("SCAN FOUND")); - break; - - case EV_TXSTART: - strcpy_P(buff, PSTR("TX START")); - break; - - case EV_TXCANCELED: - strcpy_P(buff, PSTR("TX CANCELLED")); - break; - - case EV_RXSTART: - strcpy_P(buff, PSTR("RX START")); - break; - - case EV_JOIN_TXCOMPLETE: - strcpy_P(buff, PSTR("JOIN WAIT")); - break; - - default: - sprintf_P(buff, PSTR("LMIC EV %d"), ev); - break; } - // Log & Display if asked - if (*buff) { - ESP_LOGD(TAG, "%s", buff); - sprintf(lmic_event_msg, buff); - } + // get event message + if (ev < sizeof(evNames) / sizeof(evNames[0])) + sprintf(lmic_event_msg, "%s", evNames[ev] + 3); // +3 to strip "EV_" + else + sprintf(lmic_event_msg, "LMIC event %d", ev); + + // print event + ESP_LOGD(TAG, "%s", lmic_event_msg); } // receive message handler From e8448799545d6f73069d0f9260fe34ab9b96f842 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Thu, 10 Oct 2019 23:14:28 +0200 Subject: [PATCH 74/92] resolve merge conflict --- src/lorawan.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 1c1ffe30..dcc40b3f 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -419,19 +419,6 @@ void lmictask(void *pvParameters) { // discarded. LMIC_reset(); -#if defined(CFG_eu868) - // Note that The Things Network uses the non-standard SF9BW125 data rate for - // RX2 in Europe and switches between RX1 and RX2 based on network congestion. - // Thus, to avoid occasionally join failures, we set datarate to SF9 and - // bypass the LORAWAN spec-compliant RX2 == SF12 setting - LMIC_setDrTxpow(EU868_DR_SF9, KEEP_TXPOW); -#else - // 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); -#endif - // 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 From a54033296a92cc5e057a7a4d197fe48fcbdde70b Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 11 Oct 2019 12:24:27 +0200 Subject: [PATCH 75/92] lmic event handler elaborated --- src/lorawan.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index dcc40b3f..31d324a2 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -436,8 +436,16 @@ void lmictask(void *pvParameters) { // lmic event handler void myEventCallback(void *pUserData, ev_t ev) { + // using message descriptors from LMIC library static const char *const evNames[] = {LMIC_EVENT_NAME_TABLE__INIT}; + // get current event message + if (ev < sizeof(evNames) / sizeof(evNames[0])) + sprintf(lmic_event_msg, "%s", evNames[ev] + 3); // +3 to strip "EV_" + else + sprintf(lmic_event_msg, "LMIC event %d", ev); + + // process current event message switch (ev) { case EV_JOINING: // do the network-specific setup prior to join. @@ -448,13 +456,12 @@ void myEventCallback(void *pUserData, ev_t ev) { // do the after join network-specific setup. lora_setupForNetwork(false); break; - } - // get event message - if (ev < sizeof(evNames) / sizeof(evNames[0])) - sprintf(lmic_event_msg, "%s", evNames[ev] + 3); // +3 to strip "EV_" - else - sprintf(lmic_event_msg, "LMIC event %d", ev); + case EV_JOIN_TXCOMPLETE: + // replace descriptor from library with more descriptive term + lmic_event_msg = "JOIN_WAIT"; + break; + } // print event ESP_LOGD(TAG, "%s", lmic_event_msg); From b2300d0c2330b1d7332c624e957e213c6d459c7a Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Fri, 11 Oct 2019 12:24:44 +0200 Subject: [PATCH 76/92] power.cpp sanitized --- src/power.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/power.cpp b/src/power.cpp index 7d29d5b4..6a819440 100644 --- a/src/power.cpp +++ b/src/power.cpp @@ -35,14 +35,14 @@ void power_event_IRQ(void) { ESP_LOGI(TAG, "Battery low temperature."); // display on/off - if (pmu.isPEKShortPressIRQ()) { - cfg.screenon = !cfg.screenon; - } + // if (pmu.isPEKShortPressIRQ()) { + // cfg.screenon = !cfg.screenon; + //} // shutdown power if (pmu.isPEKLongtPressIRQ()) { AXP192_power(false); // switch off Lora, GPS, display - pmu.shutdown(); + pmu.shutdown(); // switch off device } pmu.clearIRQ(); From 7e5d053ec594dba2ba8f52001bc36e6f874e9c5a Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 12 Oct 2019 14:07:55 +0200 Subject: [PATCH 77/92] lmic event msg display optimizations --- include/globals.h | 9 ++++++--- include/lorawan.h | 1 - src/configmanager.cpp | 2 +- src/display.cpp | 25 +++++++++---------------- src/lorawan.cpp | 21 +++++++++++++++++---- src/macsniff.cpp | 2 +- src/main.cpp | 6 +++--- 7 files changed, 37 insertions(+), 29 deletions(-) diff --git a/include/globals.h b/include/globals.h index a753d5fb..5ae11780 100644 --- a/include/globals.h +++ b/include/globals.h @@ -41,6 +41,9 @@ #define BLE_MODE (0x40) #define SCREEN_MODE (0x80) +// length of display buffer for lmic event messages +#define LMIC_EVENTMSG_LEN 17 + // I2C bus access control #define I2C_MUTEX_LOCK() \ (xSemaphoreTake(I2Caccess, pdMS_TO_TICKS(10)) == pdTRUE) @@ -104,9 +107,9 @@ extern std::set, Mallocator> macs; extern std::array::iterator it; extern std::array beacons; -extern configData_t cfg; // current device configuration -extern char lmic_event_msg[]; // display buffer -extern uint8_t volatile channel; // wifi channel rotation counter +extern configData_t cfg; // current device configuration +extern char lmic_event_msg[LMIC_EVENTMSG_LEN]; // display buffer +extern uint8_t volatile channel; // wifi channel rotation counter extern uint16_t volatile macs_total, macs_wifi, macs_ble, batt_voltage; // display values extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC diff --git a/include/lorawan.h b/include/lorawan.h index 6d1543d9..4341b397 100644 --- a/include/lorawan.h +++ b/include/lorawan.h @@ -20,7 +20,6 @@ #include #endif -extern QueueHandle_t LoraSendQueue; extern TaskHandle_t lmicTask, lorasendTask; // table of LORAWAN MAC commands diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 41e196e6..0fce294f 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -179,7 +179,7 @@ void saveConfig() { // set and save cfg.version void migrateVersion() { - sprintf(cfg.version, "%s", PROGVERSION); + snprintf(cfg.version, 10, "%s", PROGVERSION); ESP_LOGI(TAG, "version set to %s", cfg.version); saveConfig(); } diff --git a/src/display.cpp b/src/display.cpp index bf3521d3..364fc9ba 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -15,13 +15,15 @@ Display-Mask (128 x 64 pixel): 4|WIFI:abcde BLTH:abcde SMALL 5|RLIM:abcd Mem:abcdKB SMALL 6|27.Feb 2019 20:27:00* SMALL -7|yyyyyyyyyyyyyyyy SFab SMALL +7|yyyyyyyyyyyyy xx SFab SMALL * = char {L|G|R|?} indicates time source, inverse = clock controller is active, pulsed = pps input signal is active -y = LMIC event message; ab = payload queue length +y = LMIC event message +xx = payload sendqueue length +ab = LMIC spread factor FONT_SMALL: 6x8px = 21 chars / line FONT_NORMAL: 8x8px = 16 chars / line @@ -108,7 +110,7 @@ void init_display(uint8_t verbose) { uint8_t buf[8]; char deveui[17]; os_getDevEui((u1_t *)buf); - sprintf(deveui, "%016llX", *((uint64_t *)&buf)); + snprintf(deveui, 17, "%016llX", *((uint64_t *)&buf)); // display DEVEUI as QR code on the left oledSetContrast(30); @@ -175,7 +177,6 @@ void refreshTheDisplay(bool nextPage) { void draw_page(time_t t, uint8_t page) { char timeState; - uint8_t msgWaiting; #if (HAS_GPS) static bool wasnofix = true; #endif @@ -248,19 +249,11 @@ void draw_page(time_t t, uint8_t page) { // line 7: LORA network status #if (HAS_LORA) - // LMiC event display, display inverse if sendqueue not empty - msgWaiting = uxQueueMessagesWaiting(LoraSendQueue); - if (msgWaiting) - dp_printf(0, 7, FONT_SMALL, 1, "%-16s", lmic_event_msg); - else - dp_printf(0, 7, FONT_SMALL, 0, "%-16s", lmic_event_msg); + // LMiC event display + dp_printf(0, 7, FONT_SMALL, 0, "%-16s", lmic_event_msg); // LORA datarate, display inverse if ADR disabled - if (cfg.adrmode) - dp_printf(100, 7, FONT_SMALL, 0, "%-4s", - getSfName(updr2rps(LMIC.datarate))); - else - dp_printf(100, 7, FONT_SMALL, 1, "%-4s", - getSfName(updr2rps(LMIC.datarate))); + dp_printf(104, 7, FONT_SMALL, !cfg.adrmode, "%-4s", + getSfName(updr2rps(LMIC.datarate))); #endif // HAS_LORA break; // page0 diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 31d324a2..aad3c74d 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -346,8 +346,14 @@ void lora_enqueuedata(MessageBuffer_t *message) { ret = xQueueSendToBack(LoraSendQueue, (void *)message, (TickType_t)0); break; } - if (ret != pdTRUE) + if (ret != pdTRUE) { + snprintf(lmic_event_msg + 14, LMIC_EVENTMSG_LEN - 14, "<>"); ESP_LOGW(TAG, "LORA sendqueue is full"); + } else { + // add Lora send queue length to display + snprintf(lmic_event_msg + 14, LMIC_EVENTMSG_LEN - 14, "%2u", + uxQueueMessagesWaiting(LoraSendQueue)); + } } void lora_queuereset(void) { xQueueReset(LoraSendQueue); } @@ -438,12 +444,15 @@ void myEventCallback(void *pUserData, ev_t ev) { // using message descriptors from LMIC library static const char *const evNames[] = {LMIC_EVENT_NAME_TABLE__INIT}; + // get current length of lora send queue + uint8_t const msgWaiting = uxQueueMessagesWaiting(LoraSendQueue); // get current event message if (ev < sizeof(evNames) / sizeof(evNames[0])) - sprintf(lmic_event_msg, "%s", evNames[ev] + 3); // +3 to strip "EV_" + snprintf(lmic_event_msg, LMIC_EVENTMSG_LEN, "%-16s", + evNames[ev] + 3); // +3 to strip "EV_" else - sprintf(lmic_event_msg, "LMIC event %d", ev); + snprintf(lmic_event_msg, LMIC_EVENTMSG_LEN, "LMIC event %-04u ", ev); // process current event message switch (ev) { @@ -459,12 +468,16 @@ void myEventCallback(void *pUserData, ev_t ev) { case EV_JOIN_TXCOMPLETE: // replace descriptor from library with more descriptive term - lmic_event_msg = "JOIN_WAIT"; + snprintf(lmic_event_msg, LMIC_EVENTMSG_LEN, "%-16s", "JOIN_WAIT"); break; } // print event ESP_LOGD(TAG, "%s", lmic_event_msg); + + // add Lora send queue length to display + if (msgWaiting) + snprintf(lmic_event_msg + 14, LMIC_EVENTMSG_LEN - 14, "%2u", msgWaiting); } // receive message handler diff --git a/src/macsniff.cpp b/src/macsniff.cpp index 0b00e7c1..38a1a991 100644 --- a/src/macsniff.cpp +++ b/src/macsniff.cpp @@ -30,7 +30,7 @@ void printKey(const char *name, const uint8_t *key, uint8_t len, bool lsb) { char keystring[len + 1] = "", keybyte[3]; for (uint8_t i = 0; i < len; i++) { p = lsb ? key + len - i - 1 : key + i; - sprintf(keybyte, "%02X", *p); + snprintf(keybyte, 3, "%02X", *p); strncat(keystring, keybyte, 2); } ESP_LOGI(TAG, "%s: %s", name, keystring); diff --git a/src/main.cpp b/src/main.cpp index 79b692ef..59be9996 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,9 +76,9 @@ triggers pps 1 sec impulse // Basic Config #include "main.h" -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 +configData_t cfg; // struct holds current device configuration +char lmic_event_msg[LMIC_EVENTMSG_LEN]; // 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 From d80a41a9bf347bb2edca28f95d92c7425fc95b37 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 12 Oct 2019 14:25:04 +0200 Subject: [PATCH 78/92] event display fine tuning --- src/lorawan.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index aad3c74d..b8910a9f 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -472,12 +472,12 @@ void myEventCallback(void *pUserData, ev_t ev) { break; } - // print event - ESP_LOGD(TAG, "%s", lmic_event_msg); - // add Lora send queue length to display if (msgWaiting) snprintf(lmic_event_msg + 14, LMIC_EVENTMSG_LEN - 14, "%2u", msgWaiting); + + // print event + ESP_LOGD(TAG, "%s", lmic_event_msg); } // receive message handler From 06814d3190141417560317e94635d94f0a706d32 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 12 Oct 2019 15:59:21 +0200 Subject: [PATCH 79/92] i2c release time increased, for AXP192 chip --- include/globals.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/globals.h b/include/globals.h index 5ae11780..76b733d4 100644 --- a/include/globals.h +++ b/include/globals.h @@ -41,12 +41,12 @@ #define BLE_MODE (0x40) #define SCREEN_MODE (0x80) -// length of display buffer for lmic event messages +// length of display buffer for lmic event messages #define LMIC_EVENTMSG_LEN 17 // I2C bus access control #define I2C_MUTEX_LOCK() \ - (xSemaphoreTake(I2Caccess, pdMS_TO_TICKS(10)) == pdTRUE) + (xSemaphoreTake(I2Caccess, pdMS_TO_TICKS(DISPLAYREFRESH_MS)) == pdTRUE) #define I2C_MUTEX_UNLOCK() (xSemaphoreGive(I2Caccess)) enum sendprio_t { prio_low, prio_normal, prio_high }; From a4805660cff54305fab19147d33d0b159b0a6b48 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 12 Oct 2019 16:00:22 +0200 Subject: [PATCH 80/92] power.cpp bugfixes AXP192 i2c r/w --- src/power.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/power.cpp b/src/power.cpp index 6a819440..597f68e8 100644 --- a/src/power.cpp +++ b/src/power.cpp @@ -42,7 +42,7 @@ void power_event_IRQ(void) { // shutdown power if (pmu.isPEKLongtPressIRQ()) { AXP192_power(false); // switch off Lora, GPS, display - pmu.shutdown(); // switch off device + pmu.shutdown(); // switch off device } pmu.clearIRQ(); @@ -86,7 +86,8 @@ void AXP192_showstatus(void) { void AXP192_init(void) { - if (pmu.begin(i2c_readBytes, i2c_writeBytes, AXP192_PRIMARY_ADDRESS) == AXP_FAIL) + if (pmu.begin(i2c_readBytes, i2c_writeBytes, AXP192_PRIMARY_ADDRESS) == + AXP_FAIL) ESP_LOGI(TAG, "AXP192 PMU initialization failed"); else { @@ -127,16 +128,18 @@ uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) { Wire.write(reg); Wire.endTransmission(false); uint8_t cnt = Wire.requestFrom(addr, (uint8_t)len, (uint8_t)1); - if (!cnt) { + if (!cnt) ret = 0xFF; - } uint16_t index = 0; while (Wire.available()) { - if (index > len) - return 0xFF; + if (index > len) { + ret = 0xFF; + goto finish; + } data[index++] = Wire.read(); } + finish: I2C_MUTEX_UNLOCK(); // release i2c bus access return ret; } else { @@ -147,7 +150,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) { if (I2C_MUTEX_LOCK()) { - + uint8_t ret = 0; Wire.beginTransmission(addr); Wire.write(reg); @@ -157,8 +160,8 @@ uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) { ret = Wire.endTransmission(); I2C_MUTEX_UNLOCK(); // release i2c bus access - return ret ? 0xFF : ret; - //return ret ? ret : 0xFF; + // return ret ? 0xFF : ret; + return ret ? ret : 0xFF; } else { ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0); return 0xFF; @@ -222,12 +225,7 @@ 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 @@ -243,11 +241,11 @@ uint16_t read_voltage() { ESP_ERROR_CHECK(adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf)); adc_reading += adc_buf; } -#endif +#endif // BAT_MEASURE_ADC_UNIT 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 +#endif // BAT_MEASURE_ADC #ifdef BAT_VOLTAGE_DIVIDER voltage *= BAT_VOLTAGE_DIVIDER; From 401697b39a0e2909b8980dfcdcdc8ab800f46c6e Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sat, 12 Oct 2019 16:15:57 +0200 Subject: [PATCH 81/92] display mask finetuning --- src/display.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display.cpp b/src/display.cpp index 364fc9ba..1c7a9326 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -252,7 +252,7 @@ void draw_page(time_t t, uint8_t page) { // LMiC event display dp_printf(0, 7, FONT_SMALL, 0, "%-16s", lmic_event_msg); // LORA datarate, display inverse if ADR disabled - dp_printf(104, 7, FONT_SMALL, !cfg.adrmode, "%-4s", + dp_printf(102, 7, FONT_SMALL, !cfg.adrmode, "%-4s", getSfName(updr2rps(LMIC.datarate))); #endif // HAS_LORA From 5be1bb7fd3ecf15c0fdaae19d6acb2b01fa34103 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 15:59:32 +0200 Subject: [PATCH 82/92] ttgov21old.h flip display --- src/hal/ttgov21old.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/ttgov21old.h b/src/hal/ttgov21old.h index a19887ca..20cc4a88 100644 --- a/src/hal/ttgov21old.h +++ b/src/hal/ttgov21old.h @@ -20,7 +20,7 @@ #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature #define HAS_DISPLAY 1 -//#define DISPLAY_FLIP 1 // rotated display +#define DISPLAY_FLIP 1 // rotated display //#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 From 970807d5c1251bfd2c7b13b55bff7a8d4a48dd66 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 16:58:48 +0200 Subject: [PATCH 83/92] add display RST line handling --- src/display.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/display.cpp b/src/display.cpp index 1c7a9326..c44399fa 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -67,6 +67,14 @@ void init_display(uint8_t verbose) { ESP_LOGV(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0); else { + // is we have display RST line we toggle it to re-initialize display +#ifdef MY_OLED_RST + pinMode(MY_OLED_RST, OUTPUT); + digitalWrite(MY_OLED_RST, 0); // iniialization of SSD1306 chip is executed + delay(1); // keep RES low for at least 3us according to SSD1306 datasheet + digitalWrite(MY_OLED_RST, 1); // normal operation +#endif + // init display #ifndef DISPLAY_FLIP oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 400000L); From a7230af6d748a407b0194d86c1e93e86dc06d03e Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 16:59:03 +0200 Subject: [PATCH 84/92] i2c scan with low speed --- src/i2cscan.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/i2cscan.cpp b/src/i2cscan.cpp index c80c2af7..d6e7ff64 100644 --- a/src/i2cscan.cpp +++ b/src/i2cscan.cpp @@ -15,9 +15,11 @@ int i2c_scan(void) { // block i2c bus access if (I2C_MUTEX_LOCK()) { + // Scan at 100KHz low speed + Wire.setClock(100000); + for (addr = 8; addr <= 119; addr++) { - // scan i2c bus with no more to 100KHz Wire.beginTransmission(addr); Wire.write(addr); i2c_ret = Wire.endTransmission(); @@ -58,6 +60,9 @@ int i2c_scan(void) { ESP_LOGI(TAG, "I2C scan done, %u devices found.", devices); + // Set back to 400KHz + Wire.setClock(400000); + I2C_MUTEX_UNLOCK(); // release i2c bus access } else ESP_LOGE(TAG, "I2c bus busy - scan error"); From a4299e2e1827905a57472d1ec9d47645359a9a8a Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 16:59:38 +0200 Subject: [PATCH 85/92] move i2c scanm after display init --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 59be9996..f9bdce47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -188,9 +188,6 @@ void setup() { strcat_P(features, " PMU"); #endif - // scan i2c bus for devices - i2c_scan(); - #endif // verbose // read (and initialize on first run) runtime settings from NVRAM @@ -203,6 +200,9 @@ void setup() { init_display(!cfg.runmode); // note: blocking call #endif + // scan i2c bus for devices + i2c_scan(); + #ifdef BOARD_HAS_PSRAM assert(psramFound()); ESP_LOGI(TAG, "PSRAM found and initialized"); From d72e2cdf52dc4d7fb058df76c0450b7b891532f0 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 16:59:56 +0200 Subject: [PATCH 86/92] ttgobeam.h disable BME --- src/hal/ttgobeam.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hal/ttgobeam.h b/src/hal/ttgobeam.h index a4d81926..be9c1ff7 100644 --- a/src/hal/ttgobeam.h +++ b/src/hal/ttgobeam.h @@ -28,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 1 From f35114f3a06c9e3fea8af2c1047e6f49242e19b9 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 17:01:42 +0200 Subject: [PATCH 87/92] lorawan.cpp use explicit pinmap in os_init --- src/lorawan.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index b8910a9f..efa09187 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -48,31 +48,29 @@ class MyHalConfig_t : public Arduino_LMIC::HalConfiguration_t { public: MyHalConfig_t(){}; + + // set SPI pins to board configuration, pins may come from pins_arduino.h virtual void begin(void) override { SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); } + + // virtual void end(void) override + + // virtual ostime_t setModuleActive(bool state) override }; -MyHalConfig_t myHalConfig{}; +static MyHalConfig_t myHalConfig{}; -// LMIC pin mapping - -const lmic_pinmap lmic_pins = { +// LMIC pin mapping for Hope RFM95 / HPDtek HPD13A transceivers +static const lmic_pinmap myPinmap = { .nss = LORA_CS, .rxtx = LMIC_UNUSED_PIN, .rst = LORA_RST == NOT_A_PIN ? LMIC_UNUSED_PIN : LORA_RST, .dio = {LORA_IRQ, LORA_IO1, LORA_IO2 == NOT_A_PIN ? LMIC_UNUSED_PIN : LORA_IO2}, - // optional: set polarity of rxtx pin. - .rxtx_rx_active = 0, - // optional: set RSSI cal for listen-before-talk - // this value is in dB, and is added to RSSI - // measured prior to decision. - // Must include noise guardband! Ignored in US, - // EU, IN, other markets where LBT is not required. - .rssi_cal = 0, - // optional: override LMIC_SPI_FREQ if non-zero - .spi_freq = 0, + .rxtx_rx_active = LMIC_UNUSED_PIN, + .rssi_cal = 10, + .spi_freq = 8000000, // 8MHz .pConfig = &myHalConfig}; void lora_setupForNetwork(bool preJoin) { @@ -413,7 +411,7 @@ void lmictask(void *pvParameters) { configASSERT(((uint32_t)pvParameters) == 1); // setup LMIC stack - os_init(); // initialize lmic run-time environment + os_init_ex(&myPinmap); // initialize lmic run-time environment // register a callback for downlink messages and lmic events. // We aren't trying to write reentrant code, so pUserData is NULL. From e94c73295b06c42484bec08c5030722026b3501b Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 17:21:50 +0200 Subject: [PATCH 88/92] bugfix display vertical scrolling --- src/display.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index c44399fa..1e888f21 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -418,7 +418,7 @@ int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y, void oledScrollBufferHorizontal(uint8_t *buf, const uint16_t width, const uint16_t height, bool left) { - uint16_t col, page, idx; + uint16_t col, page, idx = 0; for (page = 0; page < height / 8; page++) { if (left) { // scroll left @@ -451,9 +451,9 @@ void oledScrollBufferVertical(uint8_t *buf, const uint16_t width, buf_col = *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8]; if (offset > 0) // scroll down - buf_col <= abs(offset); + buf_col <<= offset; else // scroll up - buf_col >= offset; + buf_col >>= abs(offset); // write back uint64_t to uint8_t display buffer *(uint64_t *)&buf[col * DISPLAY_HEIGHT / 8] = buf_col; From 88f40e5d35e53ec53950ff2cb986b657e415ba42 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 17:22:30 +0200 Subject: [PATCH 89/92] code sanitizations (compiler warnings) --- src/lorawan.cpp | 5 ++++- src/timesync.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index efa09187..398e86f4 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -450,7 +450,7 @@ void myEventCallback(void *pUserData, ev_t ev) { snprintf(lmic_event_msg, LMIC_EVENTMSG_LEN, "%-16s", evNames[ev] + 3); // +3 to strip "EV_" else - snprintf(lmic_event_msg, LMIC_EVENTMSG_LEN, "LMIC event %-04u ", ev); + snprintf(lmic_event_msg, LMIC_EVENTMSG_LEN, "LMIC event %-4u ", ev); // process current event message switch (ev) { @@ -468,6 +468,9 @@ void myEventCallback(void *pUserData, ev_t ev) { // replace descriptor from library with more descriptive term snprintf(lmic_event_msg, LMIC_EVENTMSG_LEN, "%-16s", "JOIN_WAIT"); break; + + default: + break; } // add Lora send queue length to display diff --git a/src/timesync.cpp b/src/timesync.cpp index 917140d0..f2f8d14a 100644 --- a/src/timesync.cpp +++ b/src/timesync.cpp @@ -194,7 +194,7 @@ int recv_timesync_ans(const uint8_t buf[], const uint8_t buf_len) { uint32_t timestamp_sec, *timestamp_ptr; // extract 1 byte timezone from buffer (one step being 15min * 60s = 900s) - uint32_t timezone_sec = buf[0] * 900; + // uint32_t timezone_sec = buf[0] * 900; // for future use buf++; // extract 4 bytes timestamp from buffer From 23c95d827eb9c2c565613bf577e85c8479e6afe5 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 17:35:38 +0200 Subject: [PATCH 90/92] readme.md fix --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 53f08126..a5149bf3 100644 --- a/README.md +++ b/README.md @@ -151,11 +151,14 @@ Paxcounter generates identifiers for sniffed MAC adresses and collects them temp # Display If you're using a device with OLED display, or if you add such one to the I2C bus, the device shows live data on the display. You can flip display pages showing + - recent count of pax - histogram - GPS data - BME sensor data -- Time of day +- time of day +- blank page + by pressing the button of the device. # Sensors and Peripherals From e59d7e4e2565b48f21dd30366a75b52c28db8a51 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 17:48:08 +0200 Subject: [PATCH 91/92] v1.9.6 --- platformio.ini | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index 6bc76104..1975fe69 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,16 +34,16 @@ halfile = generic.h [platformio] ; upload firmware to board with usb cable -;default_envs = usb +default_envs = usb ; upload firmware to a jfrog bintray repository ;default_envs = ota ; use latest versions of libraries -default_envs = usb +;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 = 1.9.30 +release_version = 1.9.6 ; 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 @@ -55,7 +55,8 @@ platform_espressif32 = espressif32@1.11.0 monitor_speed = 115200 upload_speed = 115200 lib_deps_lora = - MCCI LoRaWAN LMIC library@>=3.0.99 + ;MCCI LoRaWAN LMIC library@>=3.1.0 + https://github.com/mcci-catena/arduino-lmic.git#5322dd1 lib_deps_display = ss_oled@>=3.0.0 BitBang_I2C@>=1.2.0 @@ -65,16 +66,17 @@ lib_deps_matrix_display = lib_deps_rgbled = SmartLeds@>=1.1.6 lib_deps_gps = - 1655@>=1.0.2 ;TinyGPSPlus by Mikal Hart + 1655@>=1.0.2 ; #1655 TinyGPSPlus by Mikal Hart lib_deps_sensors = Adafruit Unified Sensor@>=1.0.3 Adafruit BME280 Library@>=1.0.10 lib_deps_basic = ArduinoJson@^5.13.1 - 76@>=1.2.2 ;Timezone by Jack Christensen - 274@>=2.3.3 ;RTC by Michael Miller + 76@>=1.2.2 ; #76 Timezone by Jack Christensen + 274@>=2.3.3 ; #274 RTC by Michael Miller SimpleButton - AXP202X_Library@>=1.0.1 + https://github.com/lewisxhe/AXP202X_Library.git + ;AXP202X_Library@>=1.0.1 lib_deps_all = ${common.lib_deps_basic} ${common.lib_deps_lora} From 0bc368c228c35f6504c21c6c7b29a1ff5bba6e0e Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 13 Oct 2019 17:49:22 +0200 Subject: [PATCH 92/92] paxcounter.conf default settings --- src/paxcounter.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 1f3dc167..c29d5d77 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -47,7 +47,7 @@ #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 LORADRDEFAULT 3 // 0 .. 15, LoRaWAN datarate, according to regional LoRaWAN specs [use 3 for TTN in EU] +#define LORADRDEFAULT 5 // 0 .. 15, LoRaWAN datarate, according to regional LoRaWAN specs [default = 5] #define LORATXPOWDEFAULT 14 // 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] @@ -75,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 0 // 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