From fe5da9358ebbdd1c8908d5cf57efb0f43ffef49f Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Thu, 14 Jun 2018 19:49:49 +0200 Subject: [PATCH 01/34] comments in ttgo.h files updated --- platformio.ini | 4 ++-- src/hal/ttgov2.h | 4 ++-- src/hal/ttgov21.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index b4c12689..6c3e5148 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,10 +11,10 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -env_default = heltec +;env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 -;env_default = ttgov21 +env_default = ttgov21 ;env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 diff --git a/src/hal/ttgov2.h b/src/hal/ttgov2.h index e4bb49b4..5d116241 100644 --- a/src/hal/ttgov2.h +++ b/src/hal/ttgov2.h @@ -23,8 +23,8 @@ // Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display #define OLED_RST U8X8_PIN_NONE // connected to CPU RST/EN -#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2 -#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO15 (Pin15) -- SD1306 D0 +#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2 +#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0 /* diff --git a/src/hal/ttgov21.h b/src/hal/ttgov21.h index 1e3b38ec..96617e1f 100644 --- a/src/hal/ttgov21.h +++ b/src/hal/ttgov21.h @@ -22,5 +22,5 @@ // Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display #define OLED_RST U8X8_PIN_NONE // connected to CPU RST/EN -#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2 -#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO15 (Pin15) -- SD1306 D0 \ No newline at end of file +#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2 +#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0 \ No newline at end of file From 12c6dcb0ff7d785c7aaa0be45096f759c2af2430 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 16 Jun 2018 13:18:36 +0200 Subject: [PATCH 02/34] added payload.cpp and and payload.h --- platformio.ini | 4 +-- src/payload.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ src/payload.h | 36 ++++++++++++++++++++ 3 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/payload.cpp create mode 100644 src/payload.h diff --git a/platformio.ini b/platformio.ini index 6c3e5148..9e5e47aa 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,8 +14,8 @@ ;env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 -env_default = ttgov21 -;env_default = ttgobeam +;env_default = ttgov21 +env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 ;env_default = fipy diff --git a/src/payload.cpp b/src/payload.cpp new file mode 100644 index 00000000..8d992a33 --- /dev/null +++ b/src/payload.cpp @@ -0,0 +1,89 @@ + +#include "globals.h" +#include "payload.h" + +TTNplain::TTNplain(uint8_t size) : maxsize(size) { + buffer = (uint8_t *)malloc(size); + cursor = 0; +} + +TTNplain::~TTNplain(void) { free(buffer); } + +void TTNplain::reset(void) { cursor = 0; } + +uint8_t TTNplain::getSize(void) { return cursor; } + +uint8_t *TTNplain::getBuffer(void) { + // uint8_t[cursor] result; + // memcpy(result, buffer, cursor); + // return result; + return buffer; +} + +uint8_t TTNplain::copy(uint8_t *dst) { + memcpy(dst, buffer, cursor); + return cursor; +} + +void TTNplain::addCount(uint16_t value1, uint16_t value2) { + cursor = TTN_PAYLOAD_COUNTER; + buffer[cursor] = (macs_wifi & 0xff00) >> 8; + buffer[cursor++] = macs_wifi & 0xff; + buffer[cursor++] = (macs_ble & 0xff00) >> 8; + buffer[cursor++] = macs_ble & 0xff; +} + +void TTNplain::addGPS(gpsStatus_t value) { + cursor = TTN_PAYLOAD_GPS; + buffer[cursor++] = value.latitude >> 24; + buffer[cursor++] = value.latitude >> 16; + buffer[cursor++] = value.latitude >> 8; + buffer[cursor++] = value.latitude; + buffer[cursor++] = value.longitude >> 24; + buffer[cursor++] = value.longitude >> 16; + buffer[cursor++] = value.longitude >> 8; + buffer[cursor++] = value.longitude; + buffer[cursor++] = value.satellites; + buffer[cursor++] = value.hdop >> 8; + buffer[cursor++] = value.hdop; + buffer[cursor++] = value.altitude >> 8; + buffer[cursor++] = value.altitude; +} + +void TTNplain::addConfig(configData_t value) { + cursor = TTN_PAYLOAD_CONFIG; + buffer[cursor++] = value.lorasf; + buffer[cursor++] = value.adrmode; + buffer[cursor++] = value.screensaver; + buffer[cursor++] = value.screenon; + buffer[cursor++] = value.countermode; + buffer[cursor++] = value.rssilimit >> 8; + buffer[cursor++] = value.rssilimit; + buffer[cursor++] = value.sendcycle; + buffer[cursor++] = value.wifichancycle; + buffer[cursor++] = value.blescantime; + buffer[cursor++] = value.blescan; + buffer[cursor++] = value.wifiant; + buffer[cursor++] = value.vendorfilter; + buffer[cursor++] = value.rgblum; + buffer[cursor++] = value.gpsmode; + memcpy(buffer + cursor, value.version, 10); +} + +void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { + cursor = TTN_PAYLOAD_STATUS; + buffer[cursor++] = voltage >> 8; + buffer[cursor++] = voltage; + buffer[cursor++] = uptime >> 56; + buffer[cursor++] = uptime >> 48; + buffer[cursor++] = uptime >> 40; + buffer[cursor++] = uptime >> 32; + buffer[cursor++] = uptime >> 24; + buffer[cursor++] = uptime >> 32; + buffer[cursor++] = uptime >> 16; + buffer[cursor++] = uptime >> 8; + buffer[cursor++] = (uint32_t) cputemp >> 24; + buffer[cursor++] = (uint32_t) cputemp >> 16; + buffer[cursor++] = (uint32_t) cputemp >> 8; + buffer[cursor++] = (uint32_t) cputemp; +} \ No newline at end of file diff --git a/src/payload.h b/src/payload.h new file mode 100644 index 00000000..b4069c7b --- /dev/null +++ b/src/payload.h @@ -0,0 +1,36 @@ + +#ifndef _PAYLOAD_H_ +#define _PAYLOAD_H_ + +#include + +#define TTN_PAYLOAD_COUNTER 0 +#define TTN_PAYLOAD_GPS 4 +#define TTN_PAYLOAD_CONFIG 0 +#define TTN_PAYLOAD_STATUS 0 + +class TTNplain { +public: + TTNplain(uint8_t size); + ~TTNplain(); + + void reset(void); + uint8_t getSize(void); + uint8_t *getBuffer(void); + uint8_t copy(uint8_t *buffer); + + // application payloads + void addCount(uint16_t value1, uint16_t value2); + void addGPS(gpsStatus_t value); + + // payloads for get rcommands + void addConfig(configData_t value); + void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); + +private: + uint8_t *buffer; + uint8_t maxsize; + uint8_t cursor; +}; + +#endif \ No newline at end of file From 7c03c22765413721c22457396a7bfbe4bed760e1 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 16 Jun 2018 19:50:36 +0200 Subject: [PATCH 03/34] payload converter enhanced --- README.md | 34 +++++++--------- platformio.ini | 12 ++++++ src/globals.h | 53 +++++++++---------------- src/lorawan.cpp | 38 ++++++------------ src/macsniff.cpp | 2 +- src/main.cpp | 32 ++++++++++++--- src/main.h | 36 ++++++++++++++++- src/paxcounter.conf | 6 ++- src/payload.cpp | 95 ++++++++++++++++++++++++++++++++------------- src/payload.h | 32 +++++++++++---- src/rcommand.cpp | 54 +++++++++----------------- 11 files changed, 236 insertions(+), 158 deletions(-) diff --git a/README.md b/README.md index b792602c..dccacae9 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,8 @@ Legend for RGB LED (LoPy/LoPy4/FiPy/Lolin32 only): # Payload +All data is represented in big-endian-format, as long not otherwise stated. + **LoRaWAN Port #1:** Paxcounter data @@ -140,11 +142,11 @@ function Decoder(bytes, port) { decoded.wifi = (bytes[i++] << 8) | bytes[i++]; decoded.ble = (bytes[i++] << 8) | bytes[i++]; if (bytes.length > 4) { - decoded.latitude = ( (bytes[i++]) | (bytes[i++] << 8) | (bytes[i++] << 16) | bytes[i++] << 24 ); - decoded.longitude = ( (bytes[i++]) | (bytes[i++] << 8) | (bytes[i++] << 16) | bytes[i++] << 24 ); - decoded.sats = ( bytes[i++] | (bytes[i++] << 8) ); - decoded.hdop = ( bytes[i++] | (bytes[i++] << 8) ); - decoded.altitude = ( bytes[i++] | (bytes[i++] << 8) ); + decoded.latitude = ( (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++] ); + decoded.longitude = ( (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++] ); + decoded.sats = ( bytes[i++] ); + decoded.hdop = ( bytes[i++] << 8) | (bytes[i++] ); + decoded.altitude = ( bytes[i++] << 8) | (bytes[i++] ); } } @@ -264,7 +266,7 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. 0x80 get device configuration -device answers with it's current configuration. The configuration is a C structure declared in file [globals.h](src/globals.h#L32-L50) with the following definition: +device answers with it's current configuration. The configuration is a C structure declared in file [main.h](src/main.h#L13-L31) with the following definition: byte 1: Lora SF (7..12) [default 9] byte 2: Lora TXpower (2..15) [default 15] @@ -283,25 +285,19 @@ device answers with it's current configuration. The configuration is a C structu byte 16: GPS send data mode (1=on, 0=ff) [default 1] bytes 17-27: Software version (ASCII format, terminating with zero) -0x81 get device uptime +0x81 get device status - bytes 1-8: Uptime in seconds (little endian format) - -0x82 get device cpu temperature - - bytes 1-4: Chip temperature in degrees celsius (little endian format) - -0x83 get device battery voltage - - bytes 1-2: Battery voltage in millivolt, 0 if unreadable (little endian format) + bytes 1-2: Battery voltage in millivolt, 0 if unreadable + bytes 3-10: Uptime in seconds + bytes 11-14: Chip temperature in degrees celsius 0x84 get device GPS status bytes 1-4: Latitude bytes 5-8: Longitude - byte 9-10: Number of satellites - byte 11-12: HDOP - bytes 13-14: altidute [meter] + byte 9: Number of satellites + byte 10-11: HDOP + bytes 12-13: altidute [meter] # License diff --git a/platformio.ini b/platformio.ini index 9e5e47aa..787cf3ae 100644 --- a/platformio.ini +++ b/platformio.ini @@ -27,6 +27,8 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [common_env_data] platform_espressif32 = espressif32@>=1.0.2 board_build.partitions = no_ota.csv +lib_deps_all = + LoRa Serialization@>=3.0.0 lib_deps_display = U8g2@>=2.22.14 lib_deps_rgbled = @@ -55,6 +57,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 115200 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_display} build_flags = ${common_env_data.build_flags} @@ -68,6 +71,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 115200 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_display} build_flags = ${common_env_data.build_flags} @@ -81,6 +85,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 921600 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_display} build_flags = ${common_env_data.build_flags} @@ -94,6 +99,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 921600 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_display} build_flags = ${common_env_data.build_flags} @@ -107,6 +113,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 921600 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_gps} build_flags = ${common_env_data.build_flags} @@ -120,6 +127,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 921600 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_rgbled} build_flags = ${common_env_data.build_flags} @@ -133,6 +141,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 921600 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_rgbled} build_flags = ${common_env_data.build_flags} @@ -146,6 +155,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 921600 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_rgbled} build_flags = ${common_env_data.build_flags} @@ -159,6 +169,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 256000 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_rgbled} build_flags = ${common_env_data.build_flags} @@ -172,6 +183,7 @@ board_build.partitions = ${common_env_data.board_build.partitions} monitor_speed = 115200 upload_speed = 921600 lib_deps = + ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_rgbled} build_flags = ${common_env_data.build_flags} diff --git a/src/globals.h b/src/globals.h index d9adb1b9..37567dfd 100644 --- a/src/globals.h +++ b/src/globals.h @@ -28,38 +28,7 @@ #include "rgb_led.h" #include "macsniff.h" #include "main.h" - -// Struct holding devices's runtime configuration -typedef struct { - uint8_t lorasf; // 7-12, lora spreadfactor - uint8_t txpower; // 2-15, lora tx power - uint8_t adrmode; // 0=disabled, 1=enabled - uint8_t screensaver; // 0=disabled, 1=enabled - uint8_t screenon; // 0=disabled, 1=enabled - uint8_t countermode; // 0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed - int16_t rssilimit; // threshold for rssilimiter, negative value! - uint8_t sendcycle; // payload send cycle [seconds/2] - uint8_t wifichancycle; // wifi channel switch cycle [seconds/100] - uint8_t blescantime; // BLE scan cycle duration [seconds] - uint8_t blescan; // 0=disabled, 1=enabled - uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4) - uint8_t vendorfilter; // 0=disabled, 1=enabled - uint8_t rgblum; // RGB Led luminosity (0..100%) - uint8_t gpsmode; // 0=disabled, 1=enabled - char version[10]; // Firmware version -} configData_t; - -#ifdef HAS_GPS -typedef struct { - uint32_t latitude; - uint32_t longitude; - uint8_t satellites; - uint16_t hdop; - uint16_t altitude; -} gpsStatus_t; -extern gpsStatus_t gps_status; // struct for storing gps data -extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe -#endif +#include "payload.h" extern configData_t cfg; extern uint64_t uptimecounter; @@ -69,6 +38,20 @@ extern int countermode, screensaver, adrmode, lorasf, txpower, rlim; extern uint16_t macs_total, macs_wifi, macs_ble; // MAC counters extern std::set macs; extern hw_timer_t - *channelSwitch; // hardware timer used for wifi channel switching -extern xref2u1_t rcmd_data; // buffer for rcommand results size -extern u1_t rcmd_data_size; // buffer for rcommand results size + *channelSwitch; // hardware timer used for wifi channel switching + +#ifdef HAS_GPS +extern gpsStatus_t gps_status; // struct for storing gps data +extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe +#endif + +// payload encoder +#if (PAYLOAD_ENCODER == 3) +// externe CayenneLPP payload; +#elif (PAYLOAD_ENCODER == 2) +extern TTNserialized payload; +#elif (PAYLOAD_ENCODER == 1) +extern TTNplain payload; +#else +#error "No valid payload converter defined" +#endif \ No newline at end of file diff --git a/src/lorawan.cpp b/src/lorawan.cpp index ed07f19e..fd562cb1 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -117,42 +117,28 @@ void do_send(osjob_t *j) { return; } - // prepare payload with sum of unique WIFI MACs seen - static uint8_t mydata[4]; - - mydata[0] = (macs_wifi & 0xff00) >> 8; - mydata[1] = macs_wifi & 0xff; + // Prepare payload with counter and, if applicable, gps data + payload.reset(); if (cfg.blescan) { - // append sum of unique BLE MACs seen to payload - mydata[2] = (macs_ble & 0xff00) >> 8; - mydata[3] = macs_ble & 0xff; + payload.addCount(macs_wifi, macs_ble); } else { - mydata[2] = 0; - mydata[3] = 0; + payload.addCount(macs_wifi, 0); } #ifdef HAS_GPS - static uint8_t gpsdata[18]; - if (cfg.gpsmode && gps.location.isValid()) { + if ((cfg.gpsmode) && (gps.location.isValid())) { gps_read(); - memcpy(gpsdata, mydata, 4); - memcpy(gpsdata + 4, &gps_status, sizeof(gps_status)); - ESP_LOGI(TAG, "lat=%.6f / lon=%.6f | %u Sats | HDOP=%.1f | Altitude=%u m", - gps_status.latitude / (float)1000000, - gps_status.longitude / (float)1000000, gps_status.satellites, - gps_status.hdop / (float)100, gps_status.altitude); - LMIC_setTxData2(COUNTERPORT, gpsdata, sizeof(gpsdata), - (cfg.countermode & 0x02)); - ESP_LOGI(TAG, "%d bytes queued to send", sizeof(gpsdata)); + payload.addGPS(gps_status); } else { -#endif - LMIC_setTxData2(COUNTERPORT, mydata, sizeof(mydata), - (cfg.countermode & 0x02)); - ESP_LOGI(TAG, "%d bytes queued to send", sizeof(mydata)); -#ifdef HAS_GPS + ESP_LOGI(TAG, "No valid GPS position or GPS disabled"); } #endif + + // send payload + LMIC_setTxData2(COUNTERPORT, payload.getBuffer(), payload.getSize(), + (cfg.countermode & 0x02)); + ESP_LOGI(TAG, "%d bytes queued to send", payload.getSize()); sprintf(display_lmic, "PACKET QUEUED"); // clear counter if not in cumulative counter mode diff --git a/src/macsniff.cpp b/src/macsniff.cpp index 40290731..fbe0469d 100644 --- a/src/macsniff.cpp +++ b/src/macsniff.cpp @@ -76,7 +76,7 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { } // Log scan result - ESP_LOGI(TAG, + ESP_LOGD(TAG, "%s %s RSSI %ddBi -> MAC %s -> Hash %04X -> WiFi:%d BLTH:%d -> " "%d Bytes left", added ? "new " : "known", diff --git a/src/main.cpp b/src/main.cpp index 59251284..8dee0c0e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,9 +56,7 @@ uint16_t LEDColor = COLOR_NONE; // state machine variable to set RGB LED color hw_timer_t *displaytimer = NULL; // configure hardware timer used for cyclic display refresh hw_timer_t *channelSwitch = - NULL; // configure hardware timer used for wifi channel switching -xref2u1_t rcmd_data; // buffer for rcommand results size -u1_t rcmd_data_size; // buffer for rcommand results size + NULL; // configure hardware timer used for wifi channel switching #ifdef HAS_GPS gpsStatus_t gps_status; // struct for storing gps data @@ -72,6 +70,19 @@ portMUX_TYPE timerMux = std::set macs; // associative container holds total of unique MAC // adress hashes (Wifi + BLE) +// select payload encoder +#if (PAYLOAD_ENCODER == 3) +// CayenneLPP payload(PAYLOAD_BUFFER_SIZE); +#elif (PAYLOAD_ENCODER == 2) +TTNserialized payload(PAYLOAD_BUFFER_SIZE); +#elif (PAYLOAD_ENCODER == 1) +TTNplain payload(PAYLOAD_BUFFER_SIZE); +#else +#error "No valid payload converter defined" +#endif + +// TTNplain payload(PAYLOAD_BUFFER_SIZE); + // this variables will be changed in the ISR, and read in main loop static volatile int ButtonPressedIRQ = 0, DisplayTimerIRQ = 0, ChannelTimerIRQ = 0; @@ -674,11 +685,22 @@ void loop() { } #ifdef HAS_GPS - // log NMEA status every 30 seconds, useful for debugging GPS connection - if ((uptime() % 30000) == 0) + // log NMEA status every 60 seconds, useful for debugging GPS connection + if ((uptime() % 60000) == 0) { ESP_LOGI(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d", gps.passedChecksum(), gps.failedChecksum(), gps.sentencesWithFix()); + if ((cfg.gpsmode) && (gps.location.isValid())) { + gps_read(); + ESP_LOGI(TAG, + "lat=%.6f | lon=%.6f | %u Sats | HDOP=%.1f | Altitude=%um", + gps_status.latitude / (float)1000000, + gps_status.longitude / (float)1000000, gps_status.satellites, + gps_status.hdop / (float)100, gps_status.altitude); + } else { + ESP_LOGI(TAG, "No valid GPS position or GPS disabled"); + } + } #endif vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog diff --git a/src/main.h b/src/main.h index 52f7a44f..e807d7a1 100644 --- a/src/main.h +++ b/src/main.h @@ -5,11 +5,43 @@ // program version - note: increment version after modifications to configData_t // struct!! -#define PROGVERSION "1.3.81" // use max 10 chars here! +#define PROGVERSION "1.3.82" // use max 10 chars here! #define PROGNAME "PAXCNT" //--- Declarations --- +// Struct holding devices's runtime configuration +typedef struct { + uint8_t lorasf; // 7-12, lora spreadfactor + uint8_t txpower; // 2-15, lora tx power + uint8_t adrmode; // 0=disabled, 1=enabled + uint8_t screensaver; // 0=disabled, 1=enabled + uint8_t screenon; // 0=disabled, 1=enabled + uint8_t countermode; // 0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed + int16_t rssilimit; // threshold for rssilimiter, negative value! + uint8_t sendcycle; // payload send cycle [seconds/2] + uint8_t wifichancycle; // wifi channel switch cycle [seconds/100] + uint8_t blescantime; // BLE scan cycle duration [seconds] + uint8_t blescan; // 0=disabled, 1=enabled + uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4) + uint8_t vendorfilter; // 0=disabled, 1=enabled + uint8_t rgblum; // RGB Led luminosity (0..100%) + uint8_t gpsmode; // 0=disabled, 1=enabled + char version[10]; // Firmware version +} configData_t; + +#ifdef HAS_GPS +typedef struct { + uint32_t latitude; + uint32_t longitude; + uint8_t satellites; + uint16_t hdop; + uint16_t altitude; +} gpsStatus_t; +extern gpsStatus_t gps_status; // struct for storing gps data +extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe +#endif + enum led_states { LED_OFF, LED_ON }; #if defined(CFG_eu868) @@ -35,4 +67,4 @@ void stop_BLEscan(void); #ifdef HAS_GPS void gps_read(void); void gps_loop(void *pvParameters); -#endif +#endif \ No newline at end of file diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 47432573..0c3dad85 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -35,15 +35,17 @@ #define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec. // LoRa payload send cycle --> take care of duty cycle of LoRaWAN network! <-- -#define SEND_SECS 120 // [seconds/2] -> 240 sec. +//#define SEND_SECS 120 // [seconds/2] -> 240 sec. +#define SEND_SECS 30 // [seconds/2] -> 60 sec. #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_ENCODER 2 // select payload encoder: 1 = Plain [default], 2 = Lora-hserialized, 3 = Cayenne LPP +#define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit // Default LoRa Spreadfactor #define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs #define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy #define RCMDPORT 2 // LoRaWAN Port on which device listenes for remote commands -#define GPSPORT 3 // LoRaWAN Port on which device sends gps data #define COUNTERPORT 1 // LoRaWAN Port on which device sends counts // Default RGB LED luminosity (in %) diff --git a/src/payload.cpp b/src/payload.cpp index 8d992a33..e9d30f25 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -2,7 +2,9 @@ #include "globals.h" #include "payload.h" -TTNplain::TTNplain(uint8_t size) : maxsize(size) { +/* ---------------- plain format without special encoding ---------- */ + +TTNplain::TTNplain(uint8_t size) { buffer = (uint8_t *)malloc(size); cursor = 0; } @@ -13,28 +15,16 @@ void TTNplain::reset(void) { cursor = 0; } uint8_t TTNplain::getSize(void) { return cursor; } -uint8_t *TTNplain::getBuffer(void) { - // uint8_t[cursor] result; - // memcpy(result, buffer, cursor); - // return result; - return buffer; -} - -uint8_t TTNplain::copy(uint8_t *dst) { - memcpy(dst, buffer, cursor); - return cursor; -} +uint8_t *TTNplain::getBuffer(void) { return buffer; } void TTNplain::addCount(uint16_t value1, uint16_t value2) { - cursor = TTN_PAYLOAD_COUNTER; - buffer[cursor] = (macs_wifi & 0xff00) >> 8; - buffer[cursor++] = macs_wifi & 0xff; - buffer[cursor++] = (macs_ble & 0xff00) >> 8; - buffer[cursor++] = macs_ble & 0xff; + buffer[cursor++] = value1 >> 8; + buffer[cursor++] = value1; + buffer[cursor++] = value2 >> 8; + buffer[cursor++] = value2; } void TTNplain::addGPS(gpsStatus_t value) { - cursor = TTN_PAYLOAD_GPS; buffer[cursor++] = value.latitude >> 24; buffer[cursor++] = value.latitude >> 16; buffer[cursor++] = value.latitude >> 8; @@ -51,7 +41,6 @@ void TTNplain::addGPS(gpsStatus_t value) { } void TTNplain::addConfig(configData_t value) { - cursor = TTN_PAYLOAD_CONFIG; buffer[cursor++] = value.lorasf; buffer[cursor++] = value.adrmode; buffer[cursor++] = value.screensaver; @@ -68,10 +57,10 @@ void TTNplain::addConfig(configData_t value) { buffer[cursor++] = value.rgblum; buffer[cursor++] = value.gpsmode; memcpy(buffer + cursor, value.version, 10); + cursor += 10; } void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { - cursor = TTN_PAYLOAD_STATUS; buffer[cursor++] = voltage >> 8; buffer[cursor++] = voltage; buffer[cursor++] = uptime >> 56; @@ -79,11 +68,65 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { buffer[cursor++] = uptime >> 40; buffer[cursor++] = uptime >> 32; buffer[cursor++] = uptime >> 24; - buffer[cursor++] = uptime >> 32; buffer[cursor++] = uptime >> 16; buffer[cursor++] = uptime >> 8; - buffer[cursor++] = (uint32_t) cputemp >> 24; - buffer[cursor++] = (uint32_t) cputemp >> 16; - buffer[cursor++] = (uint32_t) cputemp >> 8; - buffer[cursor++] = (uint32_t) cputemp; -} \ No newline at end of file + buffer[cursor++] = uptime; + buffer[cursor++] = (uint32_t)cputemp >> 24; + buffer[cursor++] = (uint32_t)cputemp >> 16; + buffer[cursor++] = (uint32_t)cputemp >> 8; + buffer[cursor++] = (uint32_t)cputemp; +} + +/* ---------------- packed format with LoRa serialization Encoder ---------- */ + +TTNserialized::TTNserialized(uint8_t size) { + buffer = (uint8_t *)malloc(size); + LoraEncoder message(buffer); +} + +TTNserialized::~TTNserialized(void) { free(buffer); } + +void TTNserialized::reset(void) { } + +uint8_t TTNserialized::getSize(void) { return sizeof(buffer); } + +uint8_t *TTNserialized::getBuffer(void) { return buffer; } + +void TTNserialized::addCount(uint16_t value1, uint16_t value2) { + LoraEncoder message(buffer); + message.writeUint16(value1); + message.writeUint16(value2); +} + +void TTNserialized::addGPS(gpsStatus_t value) { + LoraEncoder message(buffer); + message.writeLatLng(value.latitude, value.longitude); + message.writeUint8(value.satellites); + message.writeUint16(value.hdop); + message.writeUint16(value.altitude); +} + +void TTNserialized::addConfig(configData_t value) { + LoraEncoder message(buffer); + message.writeUint8(value.lorasf); + message.writeUint16(value.rssilimit); + message.writeUint8(value.sendcycle); + message.writeUint8(value.wifichancycle); + message.writeUint8(value.blescantime); + message.writeUint8(value.rgblum); + message.writeBitmap( + value.adrmode ? true : false, value.screensaver ? true : false, + value.screenon ? true : false, value.countermode ? true : false, + value.blescan ? true : false, value.wifiant ? true : false, + value.vendorfilter ? true : false, value.gpsmode ? true : false); +} + +void TTNserialized::addStatus(uint16_t voltage, uint64_t uptime, + float cputemp) { + LoraEncoder message(buffer); + message.writeUint16(voltage); + message.writeUnixtime(uptime); + message.writeTemperature(cputemp); +} + +/* ---------------- Cayenne LPP format ---------- */ \ No newline at end of file diff --git a/src/payload.h b/src/payload.h index b4069c7b..f5096a9a 100644 --- a/src/payload.h +++ b/src/payload.h @@ -3,11 +3,7 @@ #define _PAYLOAD_H_ #include - -#define TTN_PAYLOAD_COUNTER 0 -#define TTN_PAYLOAD_GPS 4 -#define TTN_PAYLOAD_CONFIG 0 -#define TTN_PAYLOAD_STATUS 0 +#include "LoraEncoder.h" class TTNplain { public: @@ -17,7 +13,6 @@ public: void reset(void); uint8_t getSize(void); uint8_t *getBuffer(void); - uint8_t copy(uint8_t *buffer); // application payloads void addCount(uint16_t value1, uint16_t value2); @@ -33,4 +28,27 @@ private: uint8_t cursor; }; -#endif \ No newline at end of file +class TTNserialized { +public: + TTNserialized(uint8_t size); + ~TTNserialized(); + + void reset(void); + uint8_t getSize(void); + uint8_t *getBuffer(void); + + // application payloads + void addCount(uint16_t value1, uint16_t value2); + void addGPS(gpsStatus_t value); + + // payloads for get rcommands + void addConfig(configData_t value); + void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); + +private: + uint8_t *buffer; + LoraEncoder message(byte *buffer); + //LoraEncoder(byte *buffer); +}; + +#endif diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 6b446f78..1178892a 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -27,7 +27,7 @@ void antenna_select(const uint8_t _ant); // function defined in adcread.cpp #ifdef HAS_BATTERY_PROBE -uint32_t read_voltage(void); +uint16_t read_voltage(void); #endif // function sends result of get commands to LoRaWAN network @@ -40,20 +40,13 @@ void do_transmit(osjob_t *j) { os_setTimedCallback(&rcmdjob, os_getTime() + sec2osticks(RETRANSMIT_RCMD), do_transmit); } - LMIC_setTxData2(RCMDPORT, rcmd_data, rcmd_data_size, - 0); // send data unconfirmed on RCMD Port - ESP_LOGI(TAG, "%d bytes queued to send", rcmd_data_size); + // send payload + LMIC_setTxData2(RCMDPORT, payload.getBuffer(), payload.getSize(), + (cfg.countermode & 0x02)); + ESP_LOGI(TAG, "%d bytes queued to send", payload.getSize()); sprintf(display_lmic, "PACKET QUEUED"); } -// help function to transmit result of get commands, since callback function -// do_transmit() cannot have params -void transmit(xref2u1_t mydata, u1_t mydata_size) { - rcmd_data = mydata; - rcmd_data_size = mydata_size; - do_transmit(&rcmdjob); -} - // help function to assign LoRa datarates to numeric spreadfactor values void switch_lora(uint8_t sf, uint8_t tx) { if (tx > 20) @@ -292,41 +285,33 @@ void set_lorapower(uint8_t val) { }; void get_config(uint8_t val) { - ESP_LOGI(TAG, "Remote command: get configuration"); - transmit((byte *)&cfg, sizeof(cfg)); + ESP_LOGI(TAG, "Remote command: get device configuration"); + payload.reset(); + payload.addConfig(cfg); + do_transmit(&rcmdjob); }; -void get_uptime(uint8_t val) { - ESP_LOGI(TAG, "Remote command: get uptime"); - transmit((byte *)&uptimecounter, sizeof(uptimecounter)); -}; - -void get_cputemp(uint8_t val) { - ESP_LOGI(TAG, "Remote command: get cpu temperature"); - float temp = temperatureRead(); - transmit((byte *)&temp, sizeof(temp)); -}; - -void get_voltage(uint8_t val) { - ESP_LOGI(TAG, "Remote command: get battery voltage"); +void get_status(uint8_t val) { + ESP_LOGI(TAG, "Remote command: get device status"); #ifdef HAS_BATTERY_PROBE uint16_t voltage = read_voltage(); #else uint16_t voltage = 0; #endif - transmit((byte *)&voltage, sizeof(voltage)); + payload.reset(); + payload.addStatus(voltage, uptimecounter, temperatureRead()); + do_transmit(&rcmdjob); }; void get_gps(uint8_t val) { ESP_LOGI(TAG, "Remote command: get gps status"); #ifdef HAS_GPS gps_read(); - transmit((byte *)&gps_status, sizeof(gps_status)); - ESP_LOGI(TAG, "lat=%f / lon=%f | Sats=%u | HDOP=%u | Alti=%u", - gps_status.latitude / 1000000, gps_status.longitude / 1000000, - gps_status.satellites, gps_status.hdop, gps_status.altitude); + payload.reset(); + payload.addGPS(gps_status); + do_transmit(&rcmdjob); #else - ESP_LOGE(TAG, "GPS not present"); + ESP_LOGW(TAG, "GPS function not supported"); #endif }; @@ -341,8 +326,7 @@ cmd_t table[] = {{0x01, set_rssi, true}, {0x02, set_countmode, true}, {0x0b, set_wifichancycle, true}, {0x0c, set_blescantime, true}, {0x0d, set_vendorfilter, false}, {0x0e, set_blescan, true}, {0x0f, set_wifiant, true}, {0x10, set_rgblum, true}, - {0x80, get_config, false}, {0x81, get_uptime, false}, - {0x82, get_cputemp, false}, {0x83, get_voltage, false}, + {0x80, get_config, false}, {0x81, get_status, false}, {0x84, get_gps, false}}; // check and execute remote command From 509b8b6cd338da16354d5d3b92a4be77e78f7891 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 16 Jun 2018 19:54:48 +0200 Subject: [PATCH 04/34] finishing new payload converter structure --- src/globals.h | 8 ++++---- src/main.cpp | 12 +++++------- src/paxcounter.conf | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/globals.h b/src/globals.h index 37567dfd..e9290285 100644 --- a/src/globals.h +++ b/src/globals.h @@ -46,12 +46,12 @@ extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe #endif // payload encoder -#if (PAYLOAD_ENCODER == 3) -// externe CayenneLPP payload; +#if (PAYLOAD_ENCODER == 1) +extern TTNplain payload; #elif (PAYLOAD_ENCODER == 2) extern TTNserialized payload; -#elif (PAYLOAD_ENCODER == 1) -extern TTNplain payload; +#elif (PAYLOAD_ENCODER == 3) +//extern CayenneLPP payload; #else #error "No valid payload converter defined" #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 8dee0c0e..5a3a6589 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,19 +70,17 @@ portMUX_TYPE timerMux = std::set macs; // associative container holds total of unique MAC // adress hashes (Wifi + BLE) -// select payload encoder -#if (PAYLOAD_ENCODER == 3) -// CayenneLPP payload(PAYLOAD_BUFFER_SIZE); +// initialize payload encoder +#if (PAYLOAD_ENCODER == 1) +TTNplain payload(PAYLOAD_BUFFER_SIZE); #elif (PAYLOAD_ENCODER == 2) TTNserialized payload(PAYLOAD_BUFFER_SIZE); -#elif (PAYLOAD_ENCODER == 1) -TTNplain payload(PAYLOAD_BUFFER_SIZE); +#elif (PAYLOAD_ENCODER == 3) +//CayenneLPP payload(PAYLOAD_BUFFER_SIZE); #else #error "No valid payload converter defined" #endif -// TTNplain payload(PAYLOAD_BUFFER_SIZE); - // this variables will be changed in the ISR, and read in main loop static volatile int ButtonPressedIRQ = 0, DisplayTimerIRQ = 0, ChannelTimerIRQ = 0; diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 0c3dad85..9e550d01 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -39,7 +39,7 @@ #define SEND_SECS 30 // [seconds/2] -> 60 sec. #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_ENCODER 2 // select payload encoder: 1 = Plain [default], 2 = Lora-hserialized, 3 = Cayenne LPP +#define PAYLOAD_ENCODER 1 // select payload encoder: 1 = Plain [default], 2 = Lora-hserialized, 3 = Cayenne LPP #define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit // Default LoRa Spreadfactor From ec5b1df77cfbab2e1edab5519619dc0c7a83867c Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 16 Jun 2018 20:20:19 +0200 Subject: [PATCH 05/34] payload encoder testing --- src/lorawan.cpp | 2 -- src/payload.cpp | 4 ++-- src/payload.h | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index fd562cb1..69003d9c 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -130,8 +130,6 @@ void do_send(osjob_t *j) { if ((cfg.gpsmode) && (gps.location.isValid())) { gps_read(); payload.addGPS(gps_status); - } else { - ESP_LOGI(TAG, "No valid GPS position or GPS disabled"); } #endif diff --git a/src/payload.cpp b/src/payload.cpp index e9d30f25..c1c79c86 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -81,12 +81,12 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { TTNserialized::TTNserialized(uint8_t size) { buffer = (uint8_t *)malloc(size); - LoraEncoder message(buffer); + //LoraEncoder message(buffer); } TTNserialized::~TTNserialized(void) { free(buffer); } -void TTNserialized::reset(void) { } +void TTNserialized::reset(void) { delete buffer; } uint8_t TTNserialized::getSize(void) { return sizeof(buffer); } diff --git a/src/payload.h b/src/payload.h index f5096a9a..03311c76 100644 --- a/src/payload.h +++ b/src/payload.h @@ -48,7 +48,6 @@ public: private: uint8_t *buffer; LoraEncoder message(byte *buffer); - //LoraEncoder(byte *buffer); }; #endif From 692b90d2303b64ba7bfbac0776f108e74d56fef5 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 16 Jun 2018 20:25:49 +0200 Subject: [PATCH 06/34] paxcounter.conf edit --- src/paxcounter.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 9e550d01..31423a3c 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -1,6 +1,8 @@ // ----- Paxcounter user config file ------ // // --> adapt to your needs and use case <-- +// +// Note: After editing, before "build", use "clean" button in PlatformIO! // Verbose enables serial output #define VERBOSE 1 // comment out to silence the device, for mute use build option From a6642ea8b64e4e9a9650da6587ca37bcc56faca9 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 16 Jun 2018 23:14:49 +0200 Subject: [PATCH 07/34] CayenneLPP payload encoder added (experimental) --- src/globals.h | 2 +- src/main.cpp | 2 +- src/paxcounter.conf | 3 +- src/payload.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++-- src/payload.h | 45 +++++++++++++++++++++++++----- 5 files changed, 108 insertions(+), 12 deletions(-) diff --git a/src/globals.h b/src/globals.h index e9290285..262fc4c8 100644 --- a/src/globals.h +++ b/src/globals.h @@ -51,7 +51,7 @@ extern TTNplain payload; #elif (PAYLOAD_ENCODER == 2) extern TTNserialized payload; #elif (PAYLOAD_ENCODER == 3) -//extern CayenneLPP payload; +extern CayenneLPP payload; #else #error "No valid payload converter defined" #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 5a3a6589..025365dd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,7 +76,7 @@ TTNplain payload(PAYLOAD_BUFFER_SIZE); #elif (PAYLOAD_ENCODER == 2) TTNserialized payload(PAYLOAD_BUFFER_SIZE); #elif (PAYLOAD_ENCODER == 3) -//CayenneLPP payload(PAYLOAD_BUFFER_SIZE); +CayenneLPP payload(PAYLOAD_BUFFER_SIZE); #else #error "No valid payload converter defined" #endif diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 31423a3c..b1c31537 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -41,8 +41,9 @@ #define SEND_SECS 30 // [seconds/2] -> 60 sec. #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_ENCODER 1 // select payload encoder: 1 = Plain [default], 2 = Lora-hserialized, 3 = Cayenne LPP +#define PAYLOAD_ENCODER 3 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP #define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit +#define CAYENNE_LPP 1 // uncomment this, if you need Cayenne LPP payload encoding // Default LoRa Spreadfactor #define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs diff --git a/src/payload.cpp b/src/payload.cpp index c1c79c86..f1a9df55 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -81,7 +81,7 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { TTNserialized::TTNserialized(uint8_t size) { buffer = (uint8_t *)malloc(size); - //LoraEncoder message(buffer); + // LoraEncoder message(buffer); } TTNserialized::~TTNserialized(void) { free(buffer); } @@ -129,4 +129,68 @@ void TTNserialized::addStatus(uint16_t voltage, uint64_t uptime, message.writeTemperature(cputemp); } -/* ---------------- Cayenne LPP format ---------- */ \ No newline at end of file +/* ---------------- Cayenne LPP format ---------- */ + +#ifdef CAYENNE_LPP + +CayenneLPP::CayenneLPP(uint8_t size) { + buffer = (uint8_t *)malloc(size); + cursor = 0; +} + +CayenneLPP::~CayenneLPP(void) { free(buffer); } + +void CayenneLPP::reset(void) { cursor = 0; } + +uint8_t CayenneLPP::getSize(void) { return cursor; } + +uint8_t *CayenneLPP::getBuffer(void) { return buffer; } + +void CayenneLPP::addCount(uint16_t value1, uint16_t value2) { + buffer[cursor++] = LPP_COUNT_WIFI_CHANNEL; + buffer[cursor++] = LPP_ANALOG_INPUT; + buffer[cursor++] = value1 >> 8; + buffer[cursor++] = value1; + buffer[cursor++] = LPP_COUNT_BLE_CHANNEL; + buffer[cursor++] = LPP_ANALOG_INPUT; + buffer[cursor++] = value2 >> 8; + buffer[cursor++] = value2; +} + +void CayenneLPP::addGPS(gpsStatus_t value) { + int32_t lat = value.latitude * (int32_t) 10000; + int32_t lon = value.longitude * (int32_t) 10000; + int32_t alt = value.altitude * (int32_t) 100; + + buffer[cursor++] = LPP_GPS_CHANNEL; + buffer[cursor++] = LPP_GPS; + buffer[cursor++] = lat >> 16; + buffer[cursor++] = lat >> 8; + buffer[cursor++] = lat; + buffer[cursor++] = lon >> 16; + buffer[cursor++] = lon >> 8; + buffer[cursor++] = lon; + buffer[cursor++] = alt >> 16; + buffer[cursor++] = alt >> 8; + buffer[cursor++] = alt; +} + +void CayenneLPP::addConfig(configData_t value) { + buffer[cursor++] = LPP_ADR_CHANNEL; + buffer[cursor++] = LPP_DIGITAL_INPUT; + buffer[cursor++] = value.adrmode; +} + +void CayenneLPP::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { + buffer[cursor++] = LPP_BATT_CHANNEL; + buffer[cursor++] = LPP_ANALOG_INPUT; + buffer[cursor++] = voltage >> 8; + buffer[cursor++] = voltage; + + buffer[cursor++] = LPP_TEMP_CHANNEL; + buffer[cursor++] = LPP_TEMPERATURE; + buffer[cursor++] = (uint16_t) cputemp >> 8; + buffer[cursor++] = (uint16_t) cputemp; +} + +#endif // CAYENNE_LPP \ No newline at end of file diff --git a/src/payload.h b/src/payload.h index 03311c76..ae30baf5 100644 --- a/src/payload.h +++ b/src/payload.h @@ -14,11 +14,8 @@ public: uint8_t getSize(void); uint8_t *getBuffer(void); - // application payloads void addCount(uint16_t value1, uint16_t value2); void addGPS(gpsStatus_t value); - - // payloads for get rcommands void addConfig(configData_t value); void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); @@ -37,11 +34,8 @@ public: uint8_t getSize(void); uint8_t *getBuffer(void); - // application payloads void addCount(uint16_t value1, uint16_t value2); void addGPS(gpsStatus_t value); - - // payloads for get rcommands void addConfig(configData_t value); void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); @@ -50,4 +44,41 @@ private: LoraEncoder message(byte *buffer); }; -#endif +#ifdef CAYENNE_LPP +// LPP channels +#define LPP_GPS_CHANNEL 20 +#define LPP_COUNT_WIFI_CHANNEL 21 +#define LPP_COUNT_BLE_CHANNEL 22 +#define LPP_BATT_CHANNEL 23 +#define LPP_ADR_CHANNEL 25 +#define LPP_TEMP_CHANNEL 26 +// LPP types +#define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01m +#define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed +#define LPP_DIGITAL_INPUT 0 // 1 byte +#define LPP_DIGITAL_OUTPUT 1 // 1 byte +#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed + +class CayenneLPP { +public: + CayenneLPP(uint8_t size); + ~CayenneLPP(); + + void reset(void); + uint8_t getSize(void); + uint8_t *getBuffer(void); + + void addCount(uint16_t value1, uint16_t value2); + void addGPS(gpsStatus_t value); + void addConfig(configData_t value); + void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); + +private: + uint8_t *buffer; + uint8_t maxsize; + uint8_t cursor; +}; + +#endif // CAYENNE_LPP + +#endif // _PAYLOAD_H_ From 095334a2a600cb2a690c31cb099c17b8f68d6dc4 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 00:05:26 +0200 Subject: [PATCH 08/34] new payload encoder (experimental) --- src/paxcounter.conf | 4 ++-- src/payload.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/paxcounter.conf b/src/paxcounter.conf index b1c31537..9a122198 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -41,9 +41,9 @@ #define SEND_SECS 30 // [seconds/2] -> 60 sec. #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_ENCODER 3 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP +#define PAYLOAD_ENCODER 1 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP #define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit -#define CAYENNE_LPP 1 // uncomment this, if you need Cayenne LPP payload encoding +//#define CAYENNE_LPP 1 // uncomment this, if you need Cayenne LPP payload encoding // Default LoRa Spreadfactor #define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs diff --git a/src/payload.cpp b/src/payload.cpp index f1a9df55..608bc3db 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -81,12 +81,11 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { TTNserialized::TTNserialized(uint8_t size) { buffer = (uint8_t *)malloc(size); - // LoraEncoder message(buffer); } TTNserialized::~TTNserialized(void) { free(buffer); } -void TTNserialized::reset(void) { delete buffer; } +void TTNserialized::reset(void) { } uint8_t TTNserialized::getSize(void) { return sizeof(buffer); } From 93de42e09b459dadf4a9b5b5093d4446459f6e36 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 00:25:40 +0200 Subject: [PATCH 09/34] payload encoder (experimental) --- src/globals.h | 6 +++++- src/main.cpp | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/globals.h b/src/globals.h index 262fc4c8..be2a175e 100644 --- a/src/globals.h +++ b/src/globals.h @@ -45,6 +45,7 @@ extern gpsStatus_t gps_status; // struct for storing gps data extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe #endif +/* // payload encoder #if (PAYLOAD_ENCODER == 1) extern TTNplain payload; @@ -54,4 +55,7 @@ extern TTNserialized payload; extern CayenneLPP payload; #else #error "No valid payload converter defined" -#endif \ No newline at end of file +#endif +*/ + +extern TTNplain payload; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 025365dd..277a40ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,6 +70,7 @@ portMUX_TYPE timerMux = std::set macs; // associative container holds total of unique MAC // adress hashes (Wifi + BLE) +/* // initialize payload encoder #if (PAYLOAD_ENCODER == 1) TTNplain payload(PAYLOAD_BUFFER_SIZE); @@ -80,6 +81,10 @@ CayenneLPP payload(PAYLOAD_BUFFER_SIZE); #else #error "No valid payload converter defined" #endif +*/ + +TTNplain payload(PAYLOAD_BUFFER_SIZE); + // this variables will be changed in the ISR, and read in main loop static volatile int ButtonPressedIRQ = 0, DisplayTimerIRQ = 0, From b47c58436f194d1420232a382b640dce16488cba Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 01:15:02 +0200 Subject: [PATCH 10/34] new payload encoder (experimental) --- src/globals.h | 12 ++++-------- src/main.cpp | 11 +++-------- src/paxcounter.conf | 1 - src/payload.cpp | 6 +----- src/payload.h | 31 ++++++++++++++----------------- 5 files changed, 22 insertions(+), 39 deletions(-) diff --git a/src/globals.h b/src/globals.h index be2a175e..a0473663 100644 --- a/src/globals.h +++ b/src/globals.h @@ -45,17 +45,13 @@ extern gpsStatus_t gps_status; // struct for storing gps data extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe #endif -/* // payload encoder -#if (PAYLOAD_ENCODER == 1) +#if PAYLOAD_ENCODER == 1 extern TTNplain payload; -#elif (PAYLOAD_ENCODER == 2) +#elif PAYLOAD_ENCODER == 2 extern TTNserialized payload; -#elif (PAYLOAD_ENCODER == 3) +#elif PAYLOAD_ENCODER == 3 extern CayenneLPP payload; #else #error "No valid payload converter defined" -#endif -*/ - -extern TTNplain payload; \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 277a40ef..ac5588fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,21 +70,16 @@ portMUX_TYPE timerMux = std::set macs; // associative container holds total of unique MAC // adress hashes (Wifi + BLE) -/* // initialize payload encoder -#if (PAYLOAD_ENCODER == 1) +#if PAYLOAD_ENCODER == 1 TTNplain payload(PAYLOAD_BUFFER_SIZE); -#elif (PAYLOAD_ENCODER == 2) +#elif PAYLOAD_ENCODER == 2 TTNserialized payload(PAYLOAD_BUFFER_SIZE); -#elif (PAYLOAD_ENCODER == 3) +#elif PAYLOAD_ENCODER == 3 CayenneLPP payload(PAYLOAD_BUFFER_SIZE); #else #error "No valid payload converter defined" #endif -*/ - -TTNplain payload(PAYLOAD_BUFFER_SIZE); - // this variables will be changed in the ISR, and read in main loop static volatile int ButtonPressedIRQ = 0, DisplayTimerIRQ = 0, diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 9a122198..c15f8db4 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -43,7 +43,6 @@ #define RETRANSMIT_RCMD 5 // [seconds] wait time before retransmitting rcommand results #define PAYLOAD_ENCODER 1 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP #define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit -//#define CAYENNE_LPP 1 // uncomment this, if you need Cayenne LPP payload encoding // Default LoRa Spreadfactor #define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs diff --git a/src/payload.cpp b/src/payload.cpp index 608bc3db..60fb217f 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -130,8 +130,6 @@ void TTNserialized::addStatus(uint16_t voltage, uint64_t uptime, /* ---------------- Cayenne LPP format ---------- */ -#ifdef CAYENNE_LPP - CayenneLPP::CayenneLPP(uint8_t size) { buffer = (uint8_t *)malloc(size); cursor = 0; @@ -190,6 +188,4 @@ void CayenneLPP::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { buffer[cursor++] = LPP_TEMPERATURE; buffer[cursor++] = (uint16_t) cputemp >> 8; buffer[cursor++] = (uint16_t) cputemp; -} - -#endif // CAYENNE_LPP \ No newline at end of file +} \ No newline at end of file diff --git a/src/payload.h b/src/payload.h index ae30baf5..41865006 100644 --- a/src/payload.h +++ b/src/payload.h @@ -5,6 +5,20 @@ #include #include "LoraEncoder.h" +// MyDevices CayenneLPP channels +#define LPP_GPS_CHANNEL 20 +#define LPP_COUNT_WIFI_CHANNEL 21 +#define LPP_COUNT_BLE_CHANNEL 22 +#define LPP_BATT_CHANNEL 23 +#define LPP_ADR_CHANNEL 25 +#define LPP_TEMP_CHANNEL 26 +// MyDevices CayenneLPP types +#define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01m +#define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed +#define LPP_DIGITAL_INPUT 0 // 1 byte +#define LPP_DIGITAL_OUTPUT 1 // 1 byte +#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed + class TTNplain { public: TTNplain(uint8_t size); @@ -44,21 +58,6 @@ private: LoraEncoder message(byte *buffer); }; -#ifdef CAYENNE_LPP -// LPP channels -#define LPP_GPS_CHANNEL 20 -#define LPP_COUNT_WIFI_CHANNEL 21 -#define LPP_COUNT_BLE_CHANNEL 22 -#define LPP_BATT_CHANNEL 23 -#define LPP_ADR_CHANNEL 25 -#define LPP_TEMP_CHANNEL 26 -// LPP types -#define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01m -#define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed -#define LPP_DIGITAL_INPUT 0 // 1 byte -#define LPP_DIGITAL_OUTPUT 1 // 1 byte -#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed - class CayenneLPP { public: CayenneLPP(uint8_t size); @@ -79,6 +78,4 @@ private: uint8_t cursor; }; -#endif // CAYENNE_LPP - #endif // _PAYLOAD_H_ From 013222ed7322af06333ee8c82676bbaf6da796c9 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 11:07:29 +0200 Subject: [PATCH 11/34] Cayenne LPP payload added (experimental) --- src/lorawan.cpp | 7 +------ src/main.cpp | 4 ++-- src/paxcounter.conf | 2 +- src/payload.cpp | 22 +++++++++------------- src/payload.h | 1 + 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 69003d9c..0000c618 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -119,12 +119,7 @@ void do_send(osjob_t *j) { // Prepare payload with counter and, if applicable, gps data payload.reset(); - - if (cfg.blescan) { - payload.addCount(macs_wifi, macs_ble); - } else { - payload.addCount(macs_wifi, 0); - } + payload.addCount(macs_wifi, cfg.blescan ? macs_ble : 0); #ifdef HAS_GPS if ((cfg.gpsmode) && (gps.location.isValid())) { diff --git a/src/main.cpp b/src/main.cpp index ac5588fa..3ed2cc8a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -692,8 +692,8 @@ void loop() { gps_read(); ESP_LOGI(TAG, "lat=%.6f | lon=%.6f | %u Sats | HDOP=%.1f | Altitude=%um", - gps_status.latitude / (float)1000000, - gps_status.longitude / (float)1000000, gps_status.satellites, + gps_status.latitude / (float)1e6, + gps_status.longitude / (float)1e6, gps_status.satellites, gps_status.hdop / (float)100, gps_status.altitude); } else { ESP_LOGI(TAG, "No valid GPS position or GPS disabled"); diff --git a/src/paxcounter.conf b/src/paxcounter.conf index c15f8db4..990b0e81 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -41,7 +41,7 @@ #define SEND_SECS 30 // [seconds/2] -> 60 sec. #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_ENCODER 1 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP +#define PAYLOAD_ENCODER 3 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP #define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit // Default LoRa Spreadfactor diff --git a/src/payload.cpp b/src/payload.cpp index 60fb217f..b1031295 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -79,13 +79,11 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { /* ---------------- packed format with LoRa serialization Encoder ---------- */ -TTNserialized::TTNserialized(uint8_t size) { - buffer = (uint8_t *)malloc(size); -} +TTNserialized::TTNserialized(uint8_t size) { buffer = (uint8_t *)malloc(size); } TTNserialized::~TTNserialized(void) { free(buffer); } -void TTNserialized::reset(void) { } +void TTNserialized::reset(void) { } // buggy! to be done, we need to clear the buffer here, but how? uint8_t TTNserialized::getSize(void) { return sizeof(buffer); } @@ -145,20 +143,19 @@ uint8_t *CayenneLPP::getBuffer(void) { return buffer; } void CayenneLPP::addCount(uint16_t value1, uint16_t value2) { buffer[cursor++] = LPP_COUNT_WIFI_CHANNEL; - buffer[cursor++] = LPP_ANALOG_INPUT; + buffer[cursor++] = LPP_LUMINOSITY; // workaround, type meter not found? buffer[cursor++] = value1 >> 8; buffer[cursor++] = value1; buffer[cursor++] = LPP_COUNT_BLE_CHANNEL; - buffer[cursor++] = LPP_ANALOG_INPUT; + buffer[cursor++] = LPP_LUMINOSITY; // workaround, type meter not found? buffer[cursor++] = value2 >> 8; buffer[cursor++] = value2; } void CayenneLPP::addGPS(gpsStatus_t value) { - int32_t lat = value.latitude * (int32_t) 10000; - int32_t lon = value.longitude * (int32_t) 10000; - int32_t alt = value.altitude * (int32_t) 100; - + int32_t lat = value.latitude / 100; + int32_t lon = value.longitude / 100; + int32_t alt = value.altitude; buffer[cursor++] = LPP_GPS_CHANNEL; buffer[cursor++] = LPP_GPS; buffer[cursor++] = lat >> 16; @@ -183,9 +180,8 @@ void CayenneLPP::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { buffer[cursor++] = LPP_ANALOG_INPUT; buffer[cursor++] = voltage >> 8; buffer[cursor++] = voltage; - buffer[cursor++] = LPP_TEMP_CHANNEL; buffer[cursor++] = LPP_TEMPERATURE; - buffer[cursor++] = (uint16_t) cputemp >> 8; - buffer[cursor++] = (uint16_t) cputemp; + buffer[cursor++] = (uint16_t)cputemp >> 8; + buffer[cursor++] = (uint16_t)cputemp; } \ No newline at end of file diff --git a/src/payload.h b/src/payload.h index 41865006..7e372702 100644 --- a/src/payload.h +++ b/src/payload.h @@ -18,6 +18,7 @@ #define LPP_DIGITAL_INPUT 0 // 1 byte #define LPP_DIGITAL_OUTPUT 1 // 1 byte #define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed +#define LPP_LUMINOSITY 101 // 2 bytes, 1 lux unsigned class TTNplain { public: From ce43bfd139f8d05c107f3931d2848a41748cfa15 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 11:40:52 +0200 Subject: [PATCH 12/34] compile feature list enhanced --- src/main.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3ed2cc8a..ac1d5684 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -468,6 +468,7 @@ void led_loop() { * ------------------------------------------------------------ */ void setup() { + char features[64] = ""; // disable brownout detection @@ -517,24 +518,24 @@ void setup() { // initialize led if needed #if (HAS_LED != NOT_A_PIN) pinMode(HAS_LED, OUTPUT); - strcat(features, " LED"); + strcat_P(features, " LED"); #endif #ifdef HAS_RGB_LED rgb_set_color(COLOR_PINK); - strcat(features, " RGB"); + strcat_P(features, " RGB"); #endif // initialize button handling if needed #ifdef HAS_BUTTON - strcat(features, " BTN_"); + strcat_P(features, " BTN_"); #ifdef BUTTON_PULLUP - strcat(features, "PU"); + strcat_P(features, "PU"); // install button interrupt (pullup mode) pinMode(HAS_BUTTON, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING); #else - strcat(features, "PD"); + strcat_P(features, "PD"); // install button interrupt (pulldown mode) pinMode(HAS_BUTTON, INPUT_PULLDOWN); attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING); @@ -543,17 +544,17 @@ void setup() { // initialize wifi antenna if needed #ifdef HAS_ANTENNA_SWITCH - strcat(features, " ANT"); + strcat_P(features, " ANT"); antenna_init(); #endif // initialize gps if present #ifdef HAS_GPS - strcat(features, " GPS"); + strcat_P(features, " GPS"); #endif #ifdef HAS_DISPLAY - strcat(features, " OLED"); + strcat_P(features, " OLED"); // initialize display init_display(PROGNAME, PROGVERSION); DisplayState = cfg.screenon; @@ -589,8 +590,17 @@ void setup() { timerAlarmWrite(channelSwitch, cfg.wifichancycle * 10000, true); timerAlarmEnable(channelSwitch); +// show payload encoder +#if PAYLOAD_ENCODER == 1 + strcat_P(features, " PAYLOAD_PLAIN"); +#elif PAYLOAD_ENCODER == 2 + strcat_P(features, " PAYLOAD_SERIALIZED"); +#elif PAYLOAD_ENCODER == 3 + strcat_P(features, " PAYLOAD_CAYENNE"); +#endif + // show compiled features - ESP_LOGI(TAG, "Features %s", features); + ESP_LOGI(TAG, "Features: %s", features); // output LoRaWAN keys to console #ifdef VERBOSE @@ -630,8 +640,7 @@ void setup() { } #endif -// if device has GPS and GPS function is enabled, start GPS reader task on core -// 0 +// if device has GPS and it is enabled, start GPS reader task on core 0 #ifdef HAS_GPS if (cfg.gpsmode) { ESP_LOGI(TAG, "Starting GPS task on core 0"); @@ -639,8 +648,7 @@ void setup() { } #endif - // kickoff sendjob -> joins network and rescedules sendjob for cyclic - // transmitting payload + // joins network and rescedules sendjob for cyclic transmitting payload do_send(&sendjob); } From 87910492e08b5e8a867e6a5e3e7d71a2d4e0739d Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 13:24:20 +0200 Subject: [PATCH 13/34] payload encoder fixes (experimental) --- src/TTN/plain_converter.js | 18 ++++ src/TTN/plain_decoder.js | 23 +++++ src/TTN/serialized_converter.js | 13 +++ src/TTN/serialized_decoder.js | 162 ++++++++++++++++++++++++++++++++ src/paxcounter.conf | 6 +- src/payload.cpp | 14 ++- 6 files changed, 228 insertions(+), 8 deletions(-) create mode 100644 src/TTN/plain_converter.js create mode 100644 src/TTN/plain_decoder.js create mode 100644 src/TTN/serialized_converter.js create mode 100644 src/TTN/serialized_decoder.js diff --git a/src/TTN/plain_converter.js b/src/TTN/plain_converter.js new file mode 100644 index 00000000..1302d56c --- /dev/null +++ b/src/TTN/plain_converter.js @@ -0,0 +1,18 @@ +// Converter for device payload encoder "PLAIN" +// copy&paste to TTN Console -> Applications -> PayloadFormat -> Converter + +function Converter(decoded, port) { + + var converted = decoded; + + if (port === 1) { + converted.pax = converted.ble + converted.wifi; + if (converted.hdop) { + converted.hdop /= 100; + converted.latitude /= 1000000; + converted.longitude /= 1000000; + } + } + + return converted; +} \ No newline at end of file diff --git a/src/TTN/plain_decoder.js b/src/TTN/plain_decoder.js new file mode 100644 index 00000000..9f2768c6 --- /dev/null +++ b/src/TTN/plain_decoder.js @@ -0,0 +1,23 @@ +// Decoder for device payload encoder "PLAIN" +// copy&paste to TTN Console -> Applications -> PayloadFormat -> Decoder + +function Decoder(bytes, port) { + var decoded = {}; + + if (port === 1) { + var i = 0; + + decoded.wifi = (bytes[i++] << 8) | bytes[i++]; + decoded.ble = (bytes[i++] << 8) | bytes[i++]; + + if (bytes.length > 4) { + decoded.latitude = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]); + decoded.longitude = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]); + decoded.sats = (bytes[i++]); + decoded.hdop = (bytes[i++] << 8) | (bytes[i++]); + decoded.altitude = (bytes[i++] << 8) | (bytes[i++]); + } + } + + return decoded; +} \ No newline at end of file diff --git a/src/TTN/serialized_converter.js b/src/TTN/serialized_converter.js new file mode 100644 index 00000000..d9f3a79a --- /dev/null +++ b/src/TTN/serialized_converter.js @@ -0,0 +1,13 @@ +// Converter for device payload encoder "SERIALIZED" +// copy&paste to TTN Console -> Applications -> PayloadFormat -> Converter + +function Converter(decoded, port) { + + var converted = decoded; + + if (port === 1) { + converted.pax = converted.ble + converted.wifi; + } + + return converted; +} \ No newline at end of file diff --git a/src/TTN/serialized_decoder.js b/src/TTN/serialized_decoder.js new file mode 100644 index 00000000..d928f031 --- /dev/null +++ b/src/TTN/serialized_decoder.js @@ -0,0 +1,162 @@ +// Decoder for device payload encoder "SERIALIZED" +// copy&paste to TTN Console -> Applications -> PayloadFormat -> Decoder + +function Decoder(bytes, port) { + + var decoded = {}; + + if (port === 1) { + // only counter data, no gps + if (bytes.length == 4) { + return decode(bytes, [uint16, uint16], ['wifi', 'ble']); + } + // combined counter and gps data + if (bytes.length > 4) { + return decode(bytes, [uint16, uint16, latlng, uint8, uint16, uint16], ['wifi', 'ble', 'coords', 'sats', 'hdop', 'altitude']); + } + } + + if (port === 2) { + // device status data + if (bytes.length == 10) { + return decode(bytes, [uint16, unixtime, temperature], ['voltage', 'uptime', 'cputemp']); + } + // device config data + if (bytes.length == 8) { + return decode(bytes, [uint8, uint16, uint8, uint8, uint8, bitmap], ['lorasf', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']); + } + } + +} + + +// ----- contents of /src/decoder.js -------------------------------------------- +// https://github.com/thesolarnomad/lora-serialization/blob/master/src/decoder.js + +var bytesToInt = function (bytes) { + var i = 0; + for (var x = 0; x < bytes.length; x++) { + i |= +(bytes[x] << (x * 8)); + } + return i; +}; + +var unixtime = function (bytes) { + if (bytes.length !== unixtime.BYTES) { + throw new Error('Unix time must have exactly 4 bytes'); + } + return bytesToInt(bytes); +}; +unixtime.BYTES = 4; + +var uint8 = function (bytes) { + if (bytes.length !== uint8.BYTES) { + throw new Error('int must have exactly 1 byte'); + } + return bytesToInt(bytes); +}; +uint8.BYTES = 1; + +var uint16 = function (bytes) { + if (bytes.length !== uint16.BYTES) { + throw new Error('int must have exactly 2 bytes'); + } + return bytesToInt(bytes); +}; +uint16.BYTES = 2; + +var latLng = function (bytes) { + if (bytes.length !== latLng.BYTES) { + throw new Error('Lat/Long must have exactly 8 bytes'); + } + + var lat = bytesToInt(bytes.slice(0, latLng.BYTES / 2)); + var lng = bytesToInt(bytes.slice(latLng.BYTES / 2, latLng.BYTES)); + + return [lat / 1e6, lng / 1e6]; +}; +latLng.BYTES = 8; + +var temperature = function (bytes) { + if (bytes.length !== temperature.BYTES) { + throw new Error('Temperature must have exactly 2 bytes'); + } + var isNegative = bytes[0] & 0x80; + var b = ('00000000' + Number(bytes[0]).toString(2)).slice(-8) + + ('00000000' + Number(bytes[1]).toString(2)).slice(-8); + if (isNegative) { + var arr = b.split('').map(function (x) { return !Number(x); }); + for (var i = arr.length - 1; i > 0; i--) { + arr[i] = !arr[i]; + if (arr[i]) { + break; + } + } + b = arr.map(Number).join(''); + } + var t = parseInt(b, 2); + if (isNegative) { + t = -t; + } + return t / 1e2; +}; +temperature.BYTES = 2; + +var humidity = function (bytes) { + if (bytes.length !== humidity.BYTES) { + throw new Error('Humidity must have exactly 2 bytes'); + } + + var h = bytesToInt(bytes); + return h / 1e2; +}; +humidity.BYTES = 2; + +var bitmap = function (byte) { + if (byte.length !== bitmap.BYTES) { + throw new Error('Bitmap must have exactly 1 byte'); + } + var i = bytesToInt(byte); + var bm = ('00000000' + Number(i).toString(2)).substr(-8).split('').map(Number).map(Boolean); + return ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] + .reduce(function (obj, pos, index) { + obj[pos] = bm[index]; + return obj; + }, {}); +}; +bitmap.BYTES = 1; + +var decode = function (bytes, mask, names) { + + var maskLength = mask.reduce(function (prev, cur) { + return prev + cur.BYTES; + }, 0); + if (bytes.length < maskLength) { + throw new Error('Mask length is ' + maskLength + ' whereas input is ' + bytes.length); + } + + names = names || []; + var offset = 0; + return mask + .map(function (decodeFn) { + var current = bytes.slice(offset, offset += decodeFn.BYTES); + return decodeFn(current); + }) + .reduce(function (prev, cur, idx) { + prev[names[idx] || idx] = cur; + return prev; + }, {}); +}; + +if (typeof module === 'object' && typeof module.exports !== 'undefined') { + module.exports = { + unixtime: unixtime, + uint8: uint8, + uint16: uint16, + temperature: temperature, + humidity: humidity, + latLng: latLng, + bitmap: bitmap, + decode: decode + }; +} \ No newline at end of file diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 990b0e81..0e83789e 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -37,11 +37,11 @@ #define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec. // LoRa payload send cycle --> take care of duty cycle of LoRaWAN network! <-- -//#define SEND_SECS 120 // [seconds/2] -> 240 sec. -#define SEND_SECS 30 // [seconds/2] -> 60 sec. +#define SEND_SECS 120 // [seconds/2] -> 240 sec. +//#define SEND_SECS 30 // [seconds/2] -> 60 sec. #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_ENCODER 3 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP +#define PAYLOAD_ENCODER 1 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP #define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit // Default LoRa Spreadfactor diff --git a/src/payload.cpp b/src/payload.cpp index b1031295..72c4005e 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -79,11 +79,15 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { /* ---------------- packed format with LoRa serialization Encoder ---------- */ -TTNserialized::TTNserialized(uint8_t size) { buffer = (uint8_t *)malloc(size); } +TTNserialized::TTNserialized(uint8_t size) { + buffer = (uint8_t *)malloc(size); + //LoraEncoder message(buffer); +} TTNserialized::~TTNserialized(void) { free(buffer); } -void TTNserialized::reset(void) { } // buggy! to be done, we need to clear the buffer here, but how? +void TTNserialized::reset(void) { +} // buggy! to be done, we need to clear the buffer here, but how? uint8_t TTNserialized::getSize(void) { return sizeof(buffer); } @@ -143,12 +147,12 @@ uint8_t *CayenneLPP::getBuffer(void) { return buffer; } void CayenneLPP::addCount(uint16_t value1, uint16_t value2) { buffer[cursor++] = LPP_COUNT_WIFI_CHANNEL; - buffer[cursor++] = LPP_LUMINOSITY; // workaround, type meter not found? + buffer[cursor++] = LPP_ANALOG_INPUT; // workaround, type meter not found? buffer[cursor++] = value1 >> 8; buffer[cursor++] = value1; buffer[cursor++] = LPP_COUNT_BLE_CHANNEL; - buffer[cursor++] = LPP_LUMINOSITY; // workaround, type meter not found? - buffer[cursor++] = value2 >> 8; + buffer[cursor++] = LPP_ANALOG_INPUT; // workaround, type meter not found? + buffer[cursor++] = value1 >> 8; buffer[cursor++] = value2; } From b1de323ed5c834363dc920fc514ffdf678cc1cc2 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 13:31:24 +0200 Subject: [PATCH 14/34] payload encoder fix HAS GPS --- platformio.ini | 4 ++-- src/payload.cpp | 6 ++++++ src/payload.h | 12 +++++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/platformio.ini b/platformio.ini index 787cf3ae..0caca06f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,8 +15,8 @@ ;env_default = ttgov1 ;env_default = ttgov2 ;env_default = ttgov21 -env_default = ttgobeam -;env_default = lopy +;env_default = ttgobeam +env_default = lopy ;env_default = lopy4 ;env_default = fipy ;env_default = lolin32lite diff --git a/src/payload.cpp b/src/payload.cpp index 72c4005e..54e32398 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -24,6 +24,7 @@ void TTNplain::addCount(uint16_t value1, uint16_t value2) { buffer[cursor++] = value2; } +#ifdef HAS_GPS void TTNplain::addGPS(gpsStatus_t value) { buffer[cursor++] = value.latitude >> 24; buffer[cursor++] = value.latitude >> 16; @@ -39,6 +40,7 @@ void TTNplain::addGPS(gpsStatus_t value) { buffer[cursor++] = value.altitude >> 8; buffer[cursor++] = value.altitude; } +#endif void TTNplain::addConfig(configData_t value) { buffer[cursor++] = value.lorasf; @@ -99,6 +101,7 @@ void TTNserialized::addCount(uint16_t value1, uint16_t value2) { message.writeUint16(value2); } +#ifdef HAS_GPS void TTNserialized::addGPS(gpsStatus_t value) { LoraEncoder message(buffer); message.writeLatLng(value.latitude, value.longitude); @@ -106,6 +109,7 @@ void TTNserialized::addGPS(gpsStatus_t value) { message.writeUint16(value.hdop); message.writeUint16(value.altitude); } +#endif void TTNserialized::addConfig(configData_t value) { LoraEncoder message(buffer); @@ -156,6 +160,7 @@ void CayenneLPP::addCount(uint16_t value1, uint16_t value2) { buffer[cursor++] = value2; } +#ifdef HAS_GPS void CayenneLPP::addGPS(gpsStatus_t value) { int32_t lat = value.latitude / 100; int32_t lon = value.longitude / 100; @@ -172,6 +177,7 @@ void CayenneLPP::addGPS(gpsStatus_t value) { buffer[cursor++] = alt >> 8; buffer[cursor++] = alt; } +#endif void CayenneLPP::addConfig(configData_t value) { buffer[cursor++] = LPP_ADR_CHANNEL; diff --git a/src/payload.h b/src/payload.h index 7e372702..13d3b8e1 100644 --- a/src/payload.h +++ b/src/payload.h @@ -30,9 +30,11 @@ public: uint8_t *getBuffer(void); void addCount(uint16_t value1, uint16_t value2); - void addGPS(gpsStatus_t value); void addConfig(configData_t value); void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); +#ifdef HAS_GPS + void addGPS(gpsStatus_t value); +#endif private: uint8_t *buffer; @@ -50,9 +52,11 @@ public: uint8_t *getBuffer(void); void addCount(uint16_t value1, uint16_t value2); - void addGPS(gpsStatus_t value); void addConfig(configData_t value); void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); +#ifdef HAS_GPS + void addGPS(gpsStatus_t value); +#endif private: uint8_t *buffer; @@ -69,9 +73,11 @@ public: uint8_t *getBuffer(void); void addCount(uint16_t value1, uint16_t value2); - void addGPS(gpsStatus_t value); void addConfig(configData_t value); void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); +#ifdef HAS_GPS + void addGPS(gpsStatus_t value); +#endif private: uint8_t *buffer; From b5f735a6d3842a8e543046e99925d9ee2d90f04d Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 14:01:55 +0200 Subject: [PATCH 15/34] lopy.h + lopy4.h corrected Pytrack settings --- src/hal/lopy.h | 13 +++++++------ src/hal/lopy4.h | 9 +++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/hal/lopy.h b/src/hal/lopy.h index d54004f6..b793cd5c 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -5,13 +5,14 @@ #define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0 // !!EXPERIMENTAL - not tested yet!! -// uncomment this only if your LoPy lives on a Pytrack expansion board with GPS +// uncomment this only if your LoPy runs on a Pytrack expansion board with GPS // see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf -//#define HAS_GPS 1 -//#define GPS_I2C_PINS GPIO_NUM_9, GPIO_NUM_8 // SDA, SCL -//#define GPS_I2C_ADDRESS_READ 0x21 -//#define GPS_I2C_ADDRESS_WRITE 0x20 -//#define HAS_BUTTON GPIO_NUM_4 +#define HAS_GPS 1 +#define GPS_I2C_PINS GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) +#define GPS_I2C_ADDRESS_READ 0x21 +#define GPS_I2C_ADDRESS_WRITE 0x20 +#define HAS_BUTTON GPIO_NUM_37 // (P14) +#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown // Hardware pin definitions for Pycom LoPy board #define PIN_SPI_SS GPIO_NUM_17 diff --git a/src/hal/lopy4.h b/src/hal/lopy4.h index 708a861d..52cda735 100644 --- a/src/hal/lopy4.h +++ b/src/hal/lopy4.h @@ -4,14 +4,15 @@ #define HAS_LED NOT_A_PIN // LoPy4 has no on board LED, so we use RGB LED on LoPy4 #define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0 -// !!EXPERIMENTAL - not tested yet!!f -// uncomment this only if your LoPy lives on a Pytrack expansion board with GPS +// !!EXPERIMENTAL - not tested yet!! +// uncomment this only if your LoPy runs on a Pytrack expansion board with GPS // see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf //#define HAS_GPS 1 -//#define GPS_I2C_PINS GPIO_NUM_9, GPIO_NUM_8 // SDA, SCL +//#define GPS_I2C_PINS GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) //#define GPS_I2C_ADDRESS_READ 0x21 //#define GPS_I2C_ADDRESS_WRITE 0x20 -//#define HAS_BUTTON GPIO_NUM_4 +//#define HAS_BUTTON GPIO_NUM_37 // (P14) +//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown // Hardware pin definitions for Pycom LoPy4 board #define PIN_SPI_SS GPIO_NUM_18 From 4d56e90ef06a38ba1497cb6bf9a7154cadd1ecd6 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 14:06:14 +0200 Subject: [PATCH 16/34] lopy.h set to default --- src/hal/lopy.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hal/lopy.h b/src/hal/lopy.h index b793cd5c..43a385bd 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -7,12 +7,12 @@ // !!EXPERIMENTAL - not tested yet!! // uncomment this only if your LoPy runs on a Pytrack expansion board with GPS // see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf -#define HAS_GPS 1 -#define GPS_I2C_PINS GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) -#define GPS_I2C_ADDRESS_READ 0x21 -#define GPS_I2C_ADDRESS_WRITE 0x20 -#define HAS_BUTTON GPIO_NUM_37 // (P14) -#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown +//#define HAS_GPS 1 +//#define GPS_I2C_PINS GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) +//#define GPS_I2C_ADDRESS_READ 0x21 +//#define GPS_I2C_ADDRESS_WRITE 0x20 +//#define HAS_BUTTON GPIO_NUM_37 // (P14) +#//define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown // Hardware pin definitions for Pycom LoPy board #define PIN_SPI_SS GPIO_NUM_17 From bb37aba2c36dce77ecf170f6cf98328378e305ad Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 14:06:34 +0200 Subject: [PATCH 17/34] lopy.h corrected --- src/hal/lopy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/lopy.h b/src/hal/lopy.h index 43a385bd..4932badb 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -12,7 +12,7 @@ //#define GPS_I2C_ADDRESS_READ 0x21 //#define GPS_I2C_ADDRESS_WRITE 0x20 //#define HAS_BUTTON GPIO_NUM_37 // (P14) -#//define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown +//define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown // Hardware pin definitions for Pycom LoPy board #define PIN_SPI_SS GPIO_NUM_17 From 85e9368c6e537ae4494b968feada543615a8a963 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 16:25:29 +0200 Subject: [PATCH 18/34] I2C gps testing --- platformio.ini | 6 ++++-- src/gpsread.cpp | 38 +++++++++++++++++++------------------- src/hal/lopy.h | 12 ++++++------ 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/platformio.ini b/platformio.ini index 0caca06f..eb728a80 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,8 +15,8 @@ ;env_default = ttgov1 ;env_default = ttgov2 ;env_default = ttgov21 -;env_default = ttgobeam -env_default = lopy +env_default = ttgobeam +;env_default = lopy ;env_default = lopy4 ;env_default = fipy ;env_default = lolin32lite @@ -143,6 +143,7 @@ upload_speed = 921600 lib_deps = ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_rgbled} + ${common_env_data.lib_deps_gps} build_flags = ${common_env_data.build_flags} -include "src/hal/lopy.h" @@ -157,6 +158,7 @@ upload_speed = 921600 lib_deps = ${common_env_data.lib_deps_all} ${common_env_data.lib_deps_rgbled} + ${common_env_data.lib_deps_gps} build_flags = ${common_env_data.build_flags} -include "src/hal/lopy4.h" diff --git a/src/gpsread.cpp b/src/gpsread.cpp index ebe16999..c32d0094 100644 --- a/src/gpsread.cpp +++ b/src/gpsread.cpp @@ -1,6 +1,7 @@ #ifdef HAS_GPS #include "globals.h" +#include // Local logging tag static const char TAG[] = "main"; @@ -22,8 +23,8 @@ void gps_loop(void *pvParameters) { // initialize and, if needed, configure, GPS #if defined GPS_SERIAL HardwareSerial GPS_Serial(1); -#elif defined GPS_I2C - // to be done +#elif defined GPS_QUECTEL_L76 + Wire.begin(GPS_QUECTEL_L76, 400000); // I2C connect to GPS device with 400 #endif while (1) { @@ -44,30 +45,29 @@ void gps_loop(void *pvParameters) { // after GPS function was disabled, close connect to GPS device GPS_Serial.end(); -#elif defined GPS_I2C +#elif defined GPS_QUECTEL_L76 - // I2C connect to GPS device with 100 kHz - Wire.begin(GPS_I2C_PINS, 100000); Wire.beginTransmission(GPS_I2C_ADDRESS_WRITE); - Wire.write(0x00); + Wire.write(0x00); // dummy write to start read + Wire.endTransmission(); - i2c_ret == Wire.beginTransmission(GPS_I2C_ADDRESS_READ); - if (i2c_ret == 0) { // check if device seen on i2c bus - while (cfg.gpsmode) { - // feed GPS decoder with serial NMEA data from GPS device - while (Wire.available()) { - Wire.requestFrom(GPS_I2C_ADDRESS_READ, 255); - gps.encode(Wire.read()); - vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog - } + Wire.beginTransmission(GPS_I2C_ADDRESS_READ); + while (cfg.gpsmode) { + Wire.requestFrom(GPS_I2C_ADDRESS_READ, 32); + while (Wire.available()) { + gps.encode(Wire.read()); + vTaskDelay(500 / portTICK_PERIOD_MS); // polling mode: 500ms sleep } - // after GPS function was disabled, close connect to GPS device - Wire.endTransmission(); - Wire.setClock(400000); // Set back to 400KHz to speed up OLED + ESP_LOGI(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d", + gps.passedChecksum(), gps.failedChecksum(), + gps.sentencesWithFix()); } + // after GPS function was disabled, close connect to GPS device -#endif + Wire.endTransmission(); + +#endif // GPS Type } vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog diff --git a/src/hal/lopy.h b/src/hal/lopy.h index 4932badb..81e8f646 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -7,12 +7,12 @@ // !!EXPERIMENTAL - not tested yet!! // uncomment this only if your LoPy runs on a Pytrack expansion board with GPS // see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf -//#define HAS_GPS 1 -//#define GPS_I2C_PINS GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) -//#define GPS_I2C_ADDRESS_READ 0x21 -//#define GPS_I2C_ADDRESS_WRITE 0x20 -//#define HAS_BUTTON GPIO_NUM_37 // (P14) -//define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown +#define HAS_GPS 1 +#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) +#define GPS_I2C_ADDRESS_READ 0x21 +#define GPS_I2C_ADDRESS_WRITE 0x20 +#define HAS_BUTTON GPIO_NUM_37 // (P14) +#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown // Hardware pin definitions for Pycom LoPy board #define PIN_SPI_SS GPIO_NUM_17 From 500d7dd6564ff1ba8d41f6797358b58027040dd4 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 16:26:36 +0200 Subject: [PATCH 19/34] I2C gps testing --- src/hal/lopy.h | 12 ++++++------ src/hal/lopy4.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hal/lopy.h b/src/hal/lopy.h index 81e8f646..2ddf38bc 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -7,12 +7,12 @@ // !!EXPERIMENTAL - not tested yet!! // uncomment this only if your LoPy runs on a Pytrack expansion board with GPS // see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf -#define HAS_GPS 1 -#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) -#define GPS_I2C_ADDRESS_READ 0x21 -#define GPS_I2C_ADDRESS_WRITE 0x20 -#define HAS_BUTTON GPIO_NUM_37 // (P14) -#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown +//#define HAS_GPS 1 +//#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) +//#define GPS_I2C_ADDRESS_READ 0x21 +//#define GPS_I2C_ADDRESS_WRITE 0x20 +//#define HAS_BUTTON GPIO_NUM_37 // (P14) +//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown // Hardware pin definitions for Pycom LoPy board #define PIN_SPI_SS GPIO_NUM_17 diff --git a/src/hal/lopy4.h b/src/hal/lopy4.h index 52cda735..589f7f02 100644 --- a/src/hal/lopy4.h +++ b/src/hal/lopy4.h @@ -8,7 +8,7 @@ // uncomment this only if your LoPy runs on a Pytrack expansion board with GPS // see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf //#define HAS_GPS 1 -//#define GPS_I2C_PINS GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) +//#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) //#define GPS_I2C_ADDRESS_READ 0x21 //#define GPS_I2C_ADDRESS_WRITE 0x20 //#define HAS_BUTTON GPIO_NUM_37 // (P14) From 706f90453fc3fb25929cab2bd18b3e5f430827b6 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 19:03:49 +0200 Subject: [PATCH 20/34] i2c gps read fixes --- platformio.ini | 4 ++-- src/gpsread.cpp | 10 +++++----- src/hal/lopy.h | 3 +-- src/hal/lopy4.h | 3 +-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/platformio.ini b/platformio.ini index eb728a80..b2181971 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,11 +11,11 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -;env_default = heltec +env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 ;env_default = ttgov21 -env_default = ttgobeam +;env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 ;env_default = fipy diff --git a/src/gpsread.cpp b/src/gpsread.cpp index c32d0094..d0cab92c 100644 --- a/src/gpsread.cpp +++ b/src/gpsread.cpp @@ -24,7 +24,7 @@ void gps_loop(void *pvParameters) { #if defined GPS_SERIAL HardwareSerial GPS_Serial(1); #elif defined GPS_QUECTEL_L76 - Wire.begin(GPS_QUECTEL_L76, 400000); // I2C connect to GPS device with 400 + Wire.begin(GPS_QUECTEL_L76, 400000); // I2C connect to GPS device with 400 KHz #endif while (1) { @@ -47,16 +47,16 @@ void gps_loop(void *pvParameters) { #elif defined GPS_QUECTEL_L76 - Wire.beginTransmission(GPS_I2C_ADDRESS_WRITE); + Wire.beginTransmission(GPS_ADDR); Wire.write(0x00); // dummy write to start read Wire.endTransmission(); - Wire.beginTransmission(GPS_I2C_ADDRESS_READ); + Wire.beginTransmission(GPS_ADDR); while (cfg.gpsmode) { - Wire.requestFrom(GPS_I2C_ADDRESS_READ, 32); + Wire.requestFrom(GPS_ADDR | 0x01, 32); while (Wire.available()) { gps.encode(Wire.read()); - vTaskDelay(500 / portTICK_PERIOD_MS); // polling mode: 500ms sleep + vTaskDelay(1 / portTICK_PERIOD_MS); // polling mode: 500ms sleep } ESP_LOGI(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d", diff --git a/src/hal/lopy.h b/src/hal/lopy.h index 2ddf38bc..d9d4068d 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -9,8 +9,7 @@ // see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf //#define HAS_GPS 1 //#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) -//#define GPS_I2C_ADDRESS_READ 0x21 -//#define GPS_I2C_ADDRESS_WRITE 0x20 +//#define GPS_ADDR 0x10 //#define HAS_BUTTON GPIO_NUM_37 // (P14) //#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown diff --git a/src/hal/lopy4.h b/src/hal/lopy4.h index 589f7f02..e5481f12 100644 --- a/src/hal/lopy4.h +++ b/src/hal/lopy4.h @@ -9,8 +9,7 @@ // see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf //#define HAS_GPS 1 //#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) -//#define GPS_I2C_ADDRESS_READ 0x21 -//#define GPS_I2C_ADDRESS_WRITE 0x20 +//#define GPS_ADDR 0x10 //#define HAS_BUTTON GPIO_NUM_37 // (P14) //#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown From a659168fc3d105448eeb183be6cb210c6b9704e7 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 22:41:32 +0200 Subject: [PATCH 21/34] new payload converter TTNpacked --- README.md | 42 +++--- platformio.ini | 7 +- ...lized_converter.js => packed_converter.js} | 2 +- ...erialized_decoder.js => packed_decoder.js} | 2 +- src/globals.h | 2 +- src/main.cpp | 4 +- src/paxcounter.conf | 8 +- src/payload.cpp | 134 +++++++++++++----- src/payload.h | 17 ++- 9 files changed, 145 insertions(+), 73 deletions(-) rename src/TTN/{serialized_converter.js => packed_converter.js} (82%) rename src/TTN/{serialized_decoder.js => packed_decoder.js} (98%) diff --git a/README.md b/README.md index dccacae9..954676c9 100644 --- a/README.md +++ b/README.md @@ -20,23 +20,25 @@ This can all be done with a single small and cheap ESP32 board for less than $20 # Hardware Supported ESP32 based LoRa IoT boards: -- **Heltec LoRa-32** a) -- **TTGOv1** a) -- **TTGOv2** a,d) -- **TTGOv2.1** a),e) -- **TTGO T-Beam** d),e),f) -- **Pycom LoPy** b),f)* -- **Pycom LoPy4** b),f)* -- **Pycom FiPy** b),f)* -- **LoLin32** with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) b),c) -- **LoLin32 Lite** with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) b),c) +- **Heltec LoRa-32** +- **TTGOv1** +- **TTGOv2** +- **TTGOv2.1** +- **TTGO T-Beam** +- **Pycom LoPy** +- **Pycom LoPy4** +- **Pycom FiPy** +- **LoLin32** + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) +- **LoLin32 Lite** + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) -a) on board OLED Display supported; -b) on board RGB LED supported; -c) on board Hardware unique DEVEUI supported; -d) external wiring needed, see instructions in file /hal/.h; -e) battery voltage monitoring supported; -f) on board GPS supported, *for Pycom devices with additional PyTrack board +Depending on board hardware following features are supported: +- LED +- OLED Display +- RGB LED +- button +- silicon unique ID +- battery voltage monitoring +- GPS Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory.
@@ -106,7 +108,13 @@ Legend for RGB LED (LoPy/LoPy4/FiPy/Lolin32 only): # Payload -All data is represented in big-endian-format, as long not otherwise stated. +You can select between different payload formats in [paxcounter.conf](src/paxounter.conf#L40): + +*Plain* generates human readable json fields, e.g. useful for TTN console +*Packed* generates packed json fiels, e.g. useful for own backends +*[CayenneLPP]*(https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) + +Hereafter described is the *Plain* format. All data is represented in big-endian-format. **LoRaWAN Port #1:** diff --git a/platformio.ini b/platformio.ini index b2181971..459696d9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,11 +11,11 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -env_default = heltec +;env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 ;env_default = ttgov21 -;env_default = ttgobeam +env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 ;env_default = fipy @@ -27,8 +27,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [common_env_data] platform_espressif32 = espressif32@>=1.0.2 board_build.partitions = no_ota.csv -lib_deps_all = - LoRa Serialization@>=3.0.0 +;lib_deps_all = lib_deps_display = U8g2@>=2.22.14 lib_deps_rgbled = diff --git a/src/TTN/serialized_converter.js b/src/TTN/packed_converter.js similarity index 82% rename from src/TTN/serialized_converter.js rename to src/TTN/packed_converter.js index d9f3a79a..7c35ad41 100644 --- a/src/TTN/serialized_converter.js +++ b/src/TTN/packed_converter.js @@ -1,4 +1,4 @@ -// Converter for device payload encoder "SERIALIZED" +// Converter for device payload encoder "PACKED" // copy&paste to TTN Console -> Applications -> PayloadFormat -> Converter function Converter(decoded, port) { diff --git a/src/TTN/serialized_decoder.js b/src/TTN/packed_decoder.js similarity index 98% rename from src/TTN/serialized_decoder.js rename to src/TTN/packed_decoder.js index d928f031..f7e06f52 100644 --- a/src/TTN/serialized_decoder.js +++ b/src/TTN/packed_decoder.js @@ -1,4 +1,4 @@ -// Decoder for device payload encoder "SERIALIZED" +// Decoder for device payload encoder "PACKED" // copy&paste to TTN Console -> Applications -> PayloadFormat -> Decoder function Decoder(bytes, port) { diff --git a/src/globals.h b/src/globals.h index a0473663..21c7b1a8 100644 --- a/src/globals.h +++ b/src/globals.h @@ -49,7 +49,7 @@ extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe #if PAYLOAD_ENCODER == 1 extern TTNplain payload; #elif PAYLOAD_ENCODER == 2 -extern TTNserialized payload; +extern TTNpacked payload; #elif PAYLOAD_ENCODER == 3 extern CayenneLPP payload; #else diff --git a/src/main.cpp b/src/main.cpp index ac1d5684..4808e7f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,7 +74,7 @@ std::set macs; // associative container holds total of unique MAC #if PAYLOAD_ENCODER == 1 TTNplain payload(PAYLOAD_BUFFER_SIZE); #elif PAYLOAD_ENCODER == 2 -TTNserialized payload(PAYLOAD_BUFFER_SIZE); +TTNpacked payload(PAYLOAD_BUFFER_SIZE); #elif PAYLOAD_ENCODER == 3 CayenneLPP payload(PAYLOAD_BUFFER_SIZE); #else @@ -594,7 +594,7 @@ void setup() { #if PAYLOAD_ENCODER == 1 strcat_P(features, " PAYLOAD_PLAIN"); #elif PAYLOAD_ENCODER == 2 - strcat_P(features, " PAYLOAD_SERIALIZED"); + strcat_P(features, " PAYLOAD_PACKED"); #elif PAYLOAD_ENCODER == 3 strcat_P(features, " PAYLOAD_CAYENNE"); #endif diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 0e83789e..9c762a19 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -36,12 +36,12 @@ #define WIFI_MY_COUNTRY "EU" // select locale for Wifi RF settings #define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec. -// LoRa payload send cycle --> take care of duty cycle of LoRaWAN network! <-- -#define SEND_SECS 120 // [seconds/2] -> 240 sec. -//#define SEND_SECS 30 // [seconds/2] -> 60 sec. +// LoRa payload parameters +#define PAYLOAD_ENCODER 2 // select payload encoder: 1=Plain [default], 2=Packed, 3=CayenneLPP +//#define SEND_SECS 120 // payload send cycle [seconds/2] -> 240 sec. +#define SEND_SECS 30 // payload send cycle [seconds/2] -> 60 sec. #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_ENCODER 1 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP #define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit // Default LoRa Spreadfactor diff --git a/src/payload.cpp b/src/payload.cpp index 54e32398..97d52e66 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -80,58 +80,116 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { } /* ---------------- packed format with LoRa serialization Encoder ---------- */ +// derived from +// https://github.com/thesolarnomad/lora-serialization/blob/master/src/LoraEncoder.cpp -TTNserialized::TTNserialized(uint8_t size) { - buffer = (uint8_t *)malloc(size); - //LoraEncoder message(buffer); -} +TTNpacked::TTNpacked(uint8_t size) { buffer = (uint8_t *)malloc(size); } -TTNserialized::~TTNserialized(void) { free(buffer); } +TTNpacked::~TTNpacked(void) { free(buffer); } -void TTNserialized::reset(void) { -} // buggy! to be done, we need to clear the buffer here, but how? +void TTNpacked::reset(void) { buffer = 0; } -uint8_t TTNserialized::getSize(void) { return sizeof(buffer); } +uint8_t TTNpacked::getSize(void) { return sizeof(buffer); } -uint8_t *TTNserialized::getBuffer(void) { return buffer; } +uint8_t *TTNpacked::getBuffer(void) { return buffer; } -void TTNserialized::addCount(uint16_t value1, uint16_t value2) { - LoraEncoder message(buffer); - message.writeUint16(value1); - message.writeUint16(value2); +void TTNpacked::addCount(uint16_t value1, uint16_t value2) { + writeUint16(value1); + writeUint16(value2); } #ifdef HAS_GPS -void TTNserialized::addGPS(gpsStatus_t value) { - LoraEncoder message(buffer); - message.writeLatLng(value.latitude, value.longitude); - message.writeUint8(value.satellites); - message.writeUint16(value.hdop); - message.writeUint16(value.altitude); +void TTNpacked::addGPS(gpsStatus_t value) { + writeLatLng(value.latitude, value.longitude); + writeUint8(value.satellites); + writeUint16(value.hdop); + writeUint16(value.altitude); } #endif -void TTNserialized::addConfig(configData_t value) { - LoraEncoder message(buffer); - message.writeUint8(value.lorasf); - message.writeUint16(value.rssilimit); - message.writeUint8(value.sendcycle); - message.writeUint8(value.wifichancycle); - message.writeUint8(value.blescantime); - message.writeUint8(value.rgblum); - message.writeBitmap( - value.adrmode ? true : false, value.screensaver ? true : false, - value.screenon ? true : false, value.countermode ? true : false, - value.blescan ? true : false, value.wifiant ? true : false, - value.vendorfilter ? true : false, value.gpsmode ? true : false); +void TTNpacked::addConfig(configData_t value) { + writeUint8(value.lorasf); + writeUint16(value.rssilimit); + writeUint8(value.sendcycle); + writeUint8(value.wifichancycle); + writeUint8(value.blescantime); + writeUint8(value.rgblum); + writeBitmap(value.adrmode ? true : false, value.screensaver ? true : false, + value.screenon ? true : false, value.countermode ? true : false, + value.blescan ? true : false, value.wifiant ? true : false, + value.vendorfilter ? true : false, value.gpsmode ? true : false); } -void TTNserialized::addStatus(uint16_t voltage, uint64_t uptime, - float cputemp) { - LoraEncoder message(buffer); - message.writeUint16(voltage); - message.writeUnixtime(uptime); - message.writeTemperature(cputemp); +void TTNpacked::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { + writeUint16(voltage); + writeUnixtime(uptime); + writeTemperature(cputemp); +} + +void TTNpacked::_intToBytes(byte *buf, int32_t i, uint8_t byteSize) { + for (uint8_t x = 0; x < byteSize; x++) { + buf[x] = (byte)(i >> (x * 8)); + } +} + +void TTNpacked::writeUnixtime(uint32_t unixtime) { + _intToBytes(buffer, unixtime, 4); + buffer += 4; +} + +void TTNpacked::writeLatLng(double latitude, double longitude) { + int32_t lat = latitude * 1e6; + int32_t lng = longitude * 1e6; + + _intToBytes(buffer, lat, 4); + _intToBytes(buffer + 4, lng, 4); + buffer += 8; +} + +void TTNpacked::writeUint16(uint16_t i) { + _intToBytes(buffer, i, 2); + buffer += 2; +} + +void TTNpacked::writeUint8(uint8_t i) { + _intToBytes(buffer, i, 1); + buffer += 1; +} + +void TTNpacked::writeHumidity(float humidity) { + int16_t h = (int16_t)(humidity * 100); + _intToBytes(buffer, h, 2); + buffer += 2; +} + +/** + * Uses a 16bit two's complement with two decimals, so the range is + * -327.68 to +327.67 degrees + */ +void TTNpacked::writeTemperature(float temperature) { + int16_t t = (int16_t)(temperature * 100); + if (temperature < 0) { + t = ~-t; + t = t + 1; + } + buffer[0] = (byte)((t >> 8) & 0xFF); + buffer[1] = (byte)t & 0xFF; + buffer += 2; +} + +void TTNpacked::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, + bool g, bool h) { + uint8_t bitmap = 0; + // LSB first + bitmap |= (a & 1) << 7; + bitmap |= (b & 1) << 6; + bitmap |= (c & 1) << 5; + bitmap |= (d & 1) << 4; + bitmap |= (e & 1) << 3; + bitmap |= (f & 1) << 2; + bitmap |= (g & 1) << 1; + bitmap |= (h & 1) << 0; + writeUint8(bitmap); } /* ---------------- Cayenne LPP format ---------- */ diff --git a/src/payload.h b/src/payload.h index 13d3b8e1..8899c709 100644 --- a/src/payload.h +++ b/src/payload.h @@ -3,7 +3,6 @@ #define _PAYLOAD_H_ #include -#include "LoraEncoder.h" // MyDevices CayenneLPP channels #define LPP_GPS_CHANNEL 20 @@ -42,10 +41,10 @@ private: uint8_t cursor; }; -class TTNserialized { +class TTNpacked { public: - TTNserialized(uint8_t size); - ~TTNserialized(); + TTNpacked(uint8_t size); + ~TTNpacked(); void reset(void); uint8_t getSize(void); @@ -60,7 +59,15 @@ public: private: uint8_t *buffer; - LoraEncoder message(byte *buffer); + void _intToBytes(byte *buf, int32_t i, uint8_t byteSize); + void writeUnixtime(uint32_t unixtime); + void writeLatLng(double latitude, double longitude); + void writeUint16(uint16_t i); + void writeUint8(uint8_t i); + void writeHumidity(float humidity); + void writeTemperature(float temperature); + void writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, bool g, + bool h); }; class CayenneLPP { From 7edffcc84055a4069f10a44b8e702e81b91ae21f Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 17 Jun 2018 22:45:05 +0200 Subject: [PATCH 22/34] repair platformio.ini --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 459696d9..e84d3d5f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -27,7 +27,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [common_env_data] platform_espressif32 = espressif32@>=1.0.2 board_build.partitions = no_ota.csv -;lib_deps_all = +lib_deps_all = lib_deps_display = U8g2@>=2.22.14 lib_deps_rgbled = From 3588bb284ca95ec9d49d66356ee256820329b52d Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 18 Jun 2018 00:01:14 +0200 Subject: [PATCH 23/34] packet payload fixes --- src/payload.cpp | 38 ++++++++++++++++++-------------------- src/payload.h | 4 ++-- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/payload.cpp b/src/payload.cpp index 97d52e66..86710382 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -83,13 +83,16 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { // derived from // https://github.com/thesolarnomad/lora-serialization/blob/master/src/LoraEncoder.cpp -TTNpacked::TTNpacked(uint8_t size) { buffer = (uint8_t *)malloc(size); } +TTNpacked::TTNpacked(uint8_t size) { + buffer = (uint8_t *)malloc(size); + cursor = 0; +} TTNpacked::~TTNpacked(void) { free(buffer); } -void TTNpacked::reset(void) { buffer = 0; } +void TTNpacked::reset(void) { cursor = 0; } -uint8_t TTNpacked::getSize(void) { return sizeof(buffer); } +uint8_t TTNpacked::getSize(void) { return cursor; } uint8_t *TTNpacked::getBuffer(void) { return buffer; } @@ -126,40 +129,35 @@ void TTNpacked::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { writeTemperature(cputemp); } -void TTNpacked::_intToBytes(byte *buf, int32_t i, uint8_t byteSize) { +void TTNpacked::_intToBytes(uint8_t pos, int32_t i, uint8_t byteSize) { for (uint8_t x = 0; x < byteSize; x++) { - buf[x] = (byte)(i >> (x * 8)); + buffer[x + pos] = (byte)(i >> (x * 8)); } + cursor += byteSize; } void TTNpacked::writeUnixtime(uint32_t unixtime) { - _intToBytes(buffer, unixtime, 4); - buffer += 4; + _intToBytes(cursor, unixtime, 4); } void TTNpacked::writeLatLng(double latitude, double longitude) { int32_t lat = latitude * 1e6; int32_t lng = longitude * 1e6; - - _intToBytes(buffer, lat, 4); - _intToBytes(buffer + 4, lng, 4); - buffer += 8; + _intToBytes(cursor, lat, 4); + _intToBytes(cursor, lng, 4); } void TTNpacked::writeUint16(uint16_t i) { - _intToBytes(buffer, i, 2); - buffer += 2; + _intToBytes(cursor, i, 2); } void TTNpacked::writeUint8(uint8_t i) { - _intToBytes(buffer, i, 1); - buffer += 1; + _intToBytes(cursor, i, 1); } void TTNpacked::writeHumidity(float humidity) { int16_t h = (int16_t)(humidity * 100); - _intToBytes(buffer, h, 2); - buffer += 2; + _intToBytes(cursor, h, 2); } /** @@ -172,9 +170,9 @@ void TTNpacked::writeTemperature(float temperature) { t = ~-t; t = t + 1; } - buffer[0] = (byte)((t >> 8) & 0xFF); - buffer[1] = (byte)t & 0xFF; - buffer += 2; + buffer[cursor] = (byte)((t >> 8) & 0xFF); + buffer[cursor+1] = (byte)t & 0xFF; + cursor += 2; } void TTNpacked::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, diff --git a/src/payload.h b/src/payload.h index 8899c709..a828b818 100644 --- a/src/payload.h +++ b/src/payload.h @@ -37,7 +37,6 @@ public: private: uint8_t *buffer; - uint8_t maxsize; uint8_t cursor; }; @@ -59,7 +58,8 @@ public: private: uint8_t *buffer; - void _intToBytes(byte *buf, int32_t i, uint8_t byteSize); + uint8_t cursor; + void _intToBytes(uint8_t pos, int32_t i, uint8_t byteSize); void writeUnixtime(uint32_t unixtime); void writeLatLng(double latitude, double longitude); void writeUint16(uint16_t i); From 3da1ddb804540d9753ef85971199520c8822caaa Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 18 Jun 2018 00:06:43 +0200 Subject: [PATCH 24/34] readme.md updated --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 954676c9..6a645a81 100644 --- a/README.md +++ b/README.md @@ -108,11 +108,13 @@ Legend for RGB LED (LoPy/LoPy4/FiPy/Lolin32 only): # Payload -You can select between different payload formats in [paxcounter.conf](src/paxounter.conf#L40): +You can select between different payload formats in [paxcounter.conf](src/paxcounter.conf#L40): -*Plain* generates human readable json fields, e.g. useful for TTN console -*Packed* generates packed json fiels, e.g. useful for own backends -*[CayenneLPP]*(https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) +- *Plain* generates human readable json fields, e.g. useful for TTN console + +- *Packed* generates packed json fiels, e.g. useful for own backends + +- *[CayenneLPP] (https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation)* generates MyDevices Cayenne readable fields Hereafter described is the *Plain* format. All data is represented in big-endian-format. From 8a3b24a0d23ca372f291ae418cb3b4eeb4783b2f Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 18 Jun 2018 00:08:13 +0200 Subject: [PATCH 25/34] readme.md updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6a645a81..0e5ed12b 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ You can select between different payload formats in [paxcounter.conf](src/paxcou - *Packed* generates packed json fiels, e.g. useful for own backends -- *[CayenneLPP] (https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation)* generates MyDevices Cayenne readable fields +- [*CayenneLPP*] (https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) generates MyDevices Cayenne readable fields Hereafter described is the *Plain* format. All data is represented in big-endian-format. From b69d66d7bc20dcf4c2ebfda9b2b2bc45c77d3f03 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 18 Jun 2018 00:09:21 +0200 Subject: [PATCH 26/34] readme.md updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e5ed12b..5dafcf33 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ You can select between different payload formats in [paxcounter.conf](src/paxcou - *Packed* generates packed json fiels, e.g. useful for own backends -- [*CayenneLPP*] (https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) generates MyDevices Cayenne readable fields +- [*CayenneLPP*](https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) generates MyDevices Cayenne readable fields Hereafter described is the *Plain* format. All data is represented in big-endian-format. From 8ad8512eb24a9a975b96dae480fbb91f6c19323a Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 18 Jun 2018 00:35:12 +0200 Subject: [PATCH 27/34] packed_decoder.js updated --- src/TTN/packed_decoder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index f7e06f52..af28fab4 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -118,7 +118,7 @@ var bitmap = function (byte) { } var i = bytesToInt(byte); var bm = ('00000000' + Number(i).toString(2)).substr(-8).split('').map(Number).map(Boolean); - return ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] + return ['adr', 'screensaver', 'display', 'countermode', 'blescan', 'antenna', 'filter', 'gpsmode'] .reduce(function (obj, pos, index) { obj[pos] = bm[index]; return obj; From f3ca06fa31557b7796ffb222cad761fd87939b24 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 18 Jun 2018 00:39:46 +0200 Subject: [PATCH 28/34] payload.cpp edited --- src/payload.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/payload.cpp b/src/payload.cpp index 86710382..b3b73e18 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -170,9 +170,8 @@ void TTNpacked::writeTemperature(float temperature) { t = ~-t; t = t + 1; } - buffer[cursor] = (byte)((t >> 8) & 0xFF); - buffer[cursor+1] = (byte)t & 0xFF; - cursor += 2; + buffer[cursor++] = (byte)((t >> 8) & 0xFF); + buffer[cursor++] = (byte)t & 0xFF; } void TTNpacked::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, From d2739426e58eec371b90b7087ad959983a0196ed Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 18 Jun 2018 09:15:57 +0200 Subject: [PATCH 29/34] payload.cpp fixes --- src/TTN/packed_decoder.js | 16 ++++++++-------- src/gpsread.cpp | 4 ++-- src/payload.cpp | 24 +++++++++--------------- src/payload.h | 4 ++-- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index af28fab4..8c469b9b 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -18,12 +18,12 @@ function Decoder(bytes, port) { if (port === 2) { // device status data - if (bytes.length == 10) { - return decode(bytes, [uint16, unixtime, temperature], ['voltage', 'uptime', 'cputemp']); + if (bytes.length == 12) { + return decode(bytes, [uint16, uptime, temperature], ['voltage', 'uptime', 'cputemp']); } // device config data if (bytes.length == 8) { - return decode(bytes, [uint8, uint16, uint8, uint8, uint8, bitmap], ['lorasf', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']); + return decode(bytes, [uint8, uint16, uint8, uint8, uint8, uint8, bitmap], ['lorasf', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']); } } @@ -41,13 +41,13 @@ var bytesToInt = function (bytes) { return i; }; -var unixtime = function (bytes) { - if (bytes.length !== unixtime.BYTES) { - throw new Error('Unix time must have exactly 4 bytes'); +var uptime = function (bytes) { + if (bytes.length !== uptime.BYTES) { + throw new Error('uptime must have exactly 8 bytes'); } return bytesToInt(bytes); }; -unixtime.BYTES = 4; +uptime.BYTES = 4; var uint8 = function (bytes) { if (bytes.length !== uint8.BYTES) { @@ -150,7 +150,7 @@ var decode = function (bytes, mask, names) { if (typeof module === 'object' && typeof module.exports !== 'undefined') { module.exports = { - unixtime: unixtime, + uptime: uptime, uint8: uint8, uint16: uint16, temperature: temperature, diff --git a/src/gpsread.cpp b/src/gpsread.cpp index d0cab92c..11a8cf92 100644 --- a/src/gpsread.cpp +++ b/src/gpsread.cpp @@ -8,8 +8,8 @@ static const char TAG[] = "main"; // read GPS data and cast to global struct void gps_read() { - gps_status.latitude = (uint32_t)(gps.location.lat() * 1000000); - gps_status.longitude = (uint32_t)(gps.location.lng() * 1000000); + gps_status.latitude = (uint32_t)(gps.location.lat() * 1e6); + gps_status.longitude = (uint32_t)(gps.location.lng() * 1e6); gps_status.satellites = (uint8_t)gps.satellites.value(); gps_status.hdop = (uint16_t)gps.hdop.value(); gps_status.altitude = (uint16_t)gps.altitude.meters(); diff --git a/src/payload.cpp b/src/payload.cpp index b3b73e18..dce09224 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -125,39 +125,33 @@ void TTNpacked::addConfig(configData_t value) { void TTNpacked::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { writeUint16(voltage); - writeUnixtime(uptime); + writeUptime(uptime); writeTemperature(cputemp); } -void TTNpacked::_intToBytes(uint8_t pos, int32_t i, uint8_t byteSize) { +void TTNpacked::intToBytes(uint8_t pos, int32_t i, uint8_t byteSize) { for (uint8_t x = 0; x < byteSize; x++) { buffer[x + pos] = (byte)(i >> (x * 8)); } cursor += byteSize; } -void TTNpacked::writeUnixtime(uint32_t unixtime) { - _intToBytes(cursor, unixtime, 4); +void TTNpacked::writeUptime(uint64_t uptime) { + intToBytes(cursor, uptime, 8); } void TTNpacked::writeLatLng(double latitude, double longitude) { - int32_t lat = latitude * 1e6; - int32_t lng = longitude * 1e6; - _intToBytes(cursor, lat, 4); - _intToBytes(cursor, lng, 4); + intToBytes(cursor, latitude, 4); + intToBytes(cursor, longitude, 4); } -void TTNpacked::writeUint16(uint16_t i) { - _intToBytes(cursor, i, 2); -} +void TTNpacked::writeUint16(uint16_t i) { intToBytes(cursor, i, 2); } -void TTNpacked::writeUint8(uint8_t i) { - _intToBytes(cursor, i, 1); -} +void TTNpacked::writeUint8(uint8_t i) { intToBytes(cursor, i, 1); } void TTNpacked::writeHumidity(float humidity) { int16_t h = (int16_t)(humidity * 100); - _intToBytes(cursor, h, 2); + intToBytes(cursor, h, 2); } /** diff --git a/src/payload.h b/src/payload.h index a828b818..53cda054 100644 --- a/src/payload.h +++ b/src/payload.h @@ -59,8 +59,8 @@ public: private: uint8_t *buffer; uint8_t cursor; - void _intToBytes(uint8_t pos, int32_t i, uint8_t byteSize); - void writeUnixtime(uint32_t unixtime); + void intToBytes(uint8_t pos, int32_t i, uint8_t byteSize); + void writeUptime(uint64_t unixtime); void writeLatLng(double latitude, double longitude); void writeUint16(uint16_t i); void writeUint8(uint8_t i); From d6dc4040834bbe8f024fa60b9bc1f8a6655dfd34 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 18 Jun 2018 13:13:13 +0200 Subject: [PATCH 30/34] finalizing v1.3.82 --- README.md | 10 ++++++---- platformio.ini | 4 ++-- src/TTN/packed_decoder.js | 31 ++++++++++++++++++------------- src/paxcounter.conf | 5 ++--- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 5dafcf33..4815091f 100644 --- a/README.md +++ b/README.md @@ -110,13 +110,13 @@ Legend for RGB LED (LoPy/LoPy4/FiPy/Lolin32 only): You can select between different payload formats in [paxcounter.conf](src/paxcounter.conf#L40): -- *Plain* generates human readable json fields, e.g. useful for TTN console +- ***Plain*** uses big endian format and generates json fields, e.g. useful for TTN console -- *Packed* generates packed json fiels, e.g. useful for own backends +- ***Packed*** uses little endian format and generates json fields -- [*CayenneLPP*](https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) generates MyDevices Cayenne readable fields +- [***CayenneLPP***](https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) generates MyDevices Cayenne readable fields -Hereafter described is the *Plain* format. All data is represented in big-endian-format. +Hereafter described is the default *Plain* format. **LoRaWAN Port #1:** @@ -144,6 +144,8 @@ To map a GPS capable paxcounter device and at the same time contribute to TTN co **Decoder:** ```javascript + + function Decoder(bytes, port) { var decoded = {}; diff --git a/platformio.ini b/platformio.ini index e84d3d5f..75d57140 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,11 +11,11 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -;env_default = heltec +env_default = heltec ;env_default = ttgov1 ;env_default = ttgov2 ;env_default = ttgov21 -env_default = ttgobeam +;env_default = ttgobeam ;env_default = lopy ;env_default = lopy4 ;env_default = fipy diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index 8c469b9b..d6f43ed0 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -7,22 +7,22 @@ function Decoder(bytes, port) { if (port === 1) { // only counter data, no gps - if (bytes.length == 4) { + if (bytes.length === 4) { return decode(bytes, [uint16, uint16], ['wifi', 'ble']); } // combined counter and gps data - if (bytes.length > 4) { - return decode(bytes, [uint16, uint16, latlng, uint8, uint16, uint16], ['wifi', 'ble', 'coords', 'sats', 'hdop', 'altitude']); + if (bytes.length === 17) { + return decode(bytes, [uint16, uint16, latLng, latLng, uint8, hdop, uint16], ['wifi', 'ble', 'latitude', 'longitude', 'sats', 'hdop', 'altitude']); } } if (port === 2) { // device status data - if (bytes.length == 12) { + if (bytes.length === 12) { return decode(bytes, [uint16, uptime, temperature], ['voltage', 'uptime', 'cputemp']); } // device config data - if (bytes.length == 8) { + if (bytes.length === 8) { return decode(bytes, [uint8, uint16, uint8, uint8, uint8, uint8, bitmap], ['lorasf', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']); } } @@ -67,15 +67,19 @@ uint16.BYTES = 2; var latLng = function (bytes) { if (bytes.length !== latLng.BYTES) { - throw new Error('Lat/Long must have exactly 8 bytes'); + throw new Error('Lat/Long must have exactly 4 bytes'); } - - var lat = bytesToInt(bytes.slice(0, latLng.BYTES / 2)); - var lng = bytesToInt(bytes.slice(latLng.BYTES / 2, latLng.BYTES)); - - return [lat / 1e6, lng / 1e6]; + return bytesToInt(bytes) / 1e6; }; -latLng.BYTES = 8; +latLng.BYTES = 4; + +var hdop = function (bytes) { + if (bytes.length !== hdop.BYTES) { + throw new Error('hdop must have exactly 2 bytes'); + } + return bytesToInt(bytes) / 100; +}; +hdop.BYTES = 2; var temperature = function (bytes) { if (bytes.length !== temperature.BYTES) { @@ -118,7 +122,7 @@ var bitmap = function (byte) { } var i = bytesToInt(byte); var bm = ('00000000' + Number(i).toString(2)).substr(-8).split('').map(Number).map(Boolean); - return ['adr', 'screensaver', 'display', 'countermode', 'blescan', 'antenna', 'filter', 'gpsmode'] + return ['adr', 'screensaver', 'screen', 'countermode', 'blescan', 'antenna', 'filter', 'gpsmode'] .reduce(function (obj, pos, index) { obj[pos] = bm[index]; return obj; @@ -156,6 +160,7 @@ if (typeof module === 'object' && typeof module.exports !== 'undefined') { temperature: temperature, humidity: humidity, latLng: latLng, + hdop: hdop, bitmap: bitmap, decode: decode }; diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 9c762a19..357ed009 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -37,9 +37,8 @@ #define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec. // LoRa payload parameters -#define PAYLOAD_ENCODER 2 // select payload encoder: 1=Plain [default], 2=Packed, 3=CayenneLPP -//#define SEND_SECS 120 // payload send cycle [seconds/2] -> 240 sec. -#define SEND_SECS 30 // payload send cycle [seconds/2] -> 60 sec. +#define PAYLOAD_ENCODER 1 // select payload encoder: 1=Plain [default], 2=Packed, 3=CayenneLPP +#define SEND_SECS 120 // payload send cycle [seconds/2] -> 240 sec. #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 From 57304a51c95326c40601abdc1ca00f11608b3e03 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 18 Jun 2018 13:17:10 +0200 Subject: [PATCH 31/34] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4815091f..ea32f823 100644 --- a/README.md +++ b/README.md @@ -141,11 +141,9 @@ If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) (TTN) you To map a GPS capable paxcounter device and at the same time contribute to TTN coverage mapping, you simply activate the [TTNmapper integration](https://www.thethingsnetwork.org/docs/applications/ttnmapper/) in TTN Console. Paxcounter generates ttnmapper compatible data fields. -**Decoder:** +**Decoder:** [TTN/plain_decoder.js](TTN/plain_decoder.js) ```javascript - - function Decoder(bytes, port) { var decoded = {}; @@ -166,7 +164,7 @@ function Decoder(bytes, port) { } ``` -**Converter:** +**Converter:** [TTN/plain_converter.js](TTN/plain_converter.js) ```javascript function Converter(decoded, port) { From acaf5cdc69229d9109cb8d2333c2fdc9cb74acb0 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 18 Jun 2018 13:21:07 +0200 Subject: [PATCH 32/34] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ea32f823..7d1f2cf1 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) (TTN) you To map a GPS capable paxcounter device and at the same time contribute to TTN coverage mapping, you simply activate the [TTNmapper integration](https://www.thethingsnetwork.org/docs/applications/ttnmapper/) in TTN Console. Paxcounter generates ttnmapper compatible data fields. -**Decoder:** [TTN/plain_decoder.js](TTN/plain_decoder.js) +[**plain_decoder.js**](src/TTN/plain_decoder.js) ```javascript function Decoder(bytes, port) { @@ -164,7 +164,7 @@ function Decoder(bytes, port) { } ``` -**Converter:** [TTN/plain_converter.js](TTN/plain_converter.js) +[**plain_converter.js**](src/TTN/plain_converter.js) ```javascript function Converter(decoded, port) { From deea6da0ab6e4de01ea6968e3a0843693a2927bc Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 18 Jun 2018 13:22:43 +0200 Subject: [PATCH 33/34] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7d1f2cf1..3cef8e58 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,10 @@ You can select between different payload formats in [paxcounter.conf](src/paxcou - [***CayenneLPP***](https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) generates MyDevices Cayenne readable fields +If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) (TTN) you may want to use a payload converter. Go to TTN Console - Application - Payload Formats and paste the code example below in tabs Decoder and Converter. Make sure that your application parses the fields `pax`, `ble` and `wifi`. + +To map a GPS capable paxcounter device and at the same time contribute to TTN coverage mapping, you simply activate the [TTNmapper integration](https://www.thethingsnetwork.org/docs/applications/ttnmapper/) in TTN Console. Paxcounter generates ttnmapper compatible data fields. + Hereafter described is the default *Plain* format. **LoRaWAN Port #1:** @@ -137,10 +141,6 @@ Hereafter described is the default *Plain* format. - see remote control - -If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) (TTN) you may want to use a payload converter. Go to TTN Console - Application - Payload Formats and paste the code example below in tabs Decoder and Converter. Make sure that your application parses the fields `pax`, `ble` and `wifi`. - -To map a GPS capable paxcounter device and at the same time contribute to TTN coverage mapping, you simply activate the [TTNmapper integration](https://www.thethingsnetwork.org/docs/applications/ttnmapper/) in TTN Console. Paxcounter generates ttnmapper compatible data fields. - [**plain_decoder.js**](src/TTN/plain_decoder.js) ```javascript From 370ae9820cfdb9941221a763d06dea84e0ec3866 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 18 Jun 2018 13:25:18 +0200 Subject: [PATCH 34/34] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cef8e58..d07d06bb 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ function Decoder(bytes, port) { if (bytes.length > 4) { decoded.latitude = ( (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++] ); decoded.longitude = ( (bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++] ); - decoded.sats = ( bytes[i++] ); + decoded.sats = ( bytes[i++] ); decoded.hdop = ( bytes[i++] << 8) | (bytes[i++] ); decoded.altitude = ( bytes[i++] << 8) | (bytes[i++] ); }