commit
						ac65c3e27c
					
				| @ -167,6 +167,10 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering. | ||||
| 	bytes 10-11:	HDOP | ||||
| 	bytes 12-13:	Altitude [meter] | ||||
| 
 | ||||
| **Port #5:** Button pressed signal | ||||
| 
 | ||||
| 	byte 1:		static value 0x01 | ||||
| 
 | ||||
| 
 | ||||
| [**plain_decoder.js**](src/TTN/plain_decoder.js) | ||||
| 
 | ||||
|  | ||||
| @ -11,11 +11,11 @@ | ||||
| 
 | ||||
| ; ---> SELECT TARGET PLATFORM HERE! <--- | ||||
| [platformio] | ||||
| ;env_default = generic | ||||
| env_default = generic | ||||
| ;env_default = heltec | ||||
| ;env_default = ttgov1 | ||||
| ;env_default = ttgov2 | ||||
| env_default = ttgov21 | ||||
| ;env_default = ttgov21 | ||||
| ;env_default = ttgobeam | ||||
| ;env_default = lopy | ||||
| ;env_default = lopy4 | ||||
| @ -28,7 +28,6 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng | ||||
| 
 | ||||
| [common_env_data] | ||||
| platform_espressif32 = espressif32@1.0.2 | ||||
| ;platform_espressif32 = espressif32@1.1.2 | ||||
| ;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage | ||||
| board_build.partitions = no_ota.csv | ||||
| lib_deps_all = | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* switches wifi antenna, if board has switch  internal / external antenna */ | ||||
| /* switches wifi antenna, if board has switch internal / external antenna */ | ||||
| 
 | ||||
| #ifdef HAS_ANTENNA_SWITCH | ||||
| 
 | ||||
|  | ||||
| @ -13,6 +13,8 @@ const char lora_datarate[] = {"1211100908077BFSNA"}; | ||||
| const char lora_datarate[] = {"100908078CNA121110090807"}; | ||||
| #endif | ||||
| 
 | ||||
| uint8_t DisplayState = 0; | ||||
| 
 | ||||
| // helper function, prints a hex key on display
 | ||||
| void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) { | ||||
|   const uint8_t *p; | ||||
| @ -107,16 +109,22 @@ void refreshDisplay() { | ||||
|   u8x8.draw2x2String(0, 0, | ||||
|                      buff); // display number on unique macs total Wifi + BLE
 | ||||
| 
 | ||||
|   // update GPS status (line 2)
 | ||||
| // update Battery status (line 2)
 | ||||
| #ifdef HAS_BATTERY_PROBE | ||||
|   u8x8.setCursor(0, 2); | ||||
|   u8x8.printf("B:%.1fV", read_voltage() / 1000.0); | ||||
| #endif | ||||
| 
 | ||||
| // update GPS status (line 2)
 | ||||
| #ifdef HAS_GPS | ||||
|   u8x8.setCursor(7, 2); | ||||
|   u8x8.setCursor(8, 2); | ||||
|   if (!gps.location.isValid()) // if no fix then display Sats value inverse
 | ||||
|   { | ||||
|     u8x8.setInverseFont(1); | ||||
|     u8x8.printf("Sats: %.3d", gps.satellites.value()); | ||||
|     u8x8.printf("Sat:%.3d", gps.satellites.value()); | ||||
|     u8x8.setInverseFont(0); | ||||
|   } else | ||||
|     u8x8.printf("Sats: %.3d", gps.satellites.value()); | ||||
|     u8x8.printf("Sat:%.3d", gps.satellites.value()); | ||||
| #endif | ||||
| 
 | ||||
|     // update bluetooth counter + LoRa SF (line 3)
 | ||||
|  | ||||
| @ -3,6 +3,8 @@ | ||||
| 
 | ||||
| #include <U8x8lib.h> | ||||
| 
 | ||||
| extern uint8_t DisplayState; | ||||
| 
 | ||||
| void init_display(const char *Productname, const char *Version); | ||||
| void refreshDisplay(void); | ||||
| void DisplayKey(const uint8_t *key, uint8_t len, bool lsb); | ||||
|  | ||||
| @ -5,10 +5,10 @@ | ||||
| #include <Arduino.h> | ||||
| 
 | ||||
| // needed for ESP_LOGx on arduino framework
 | ||||
| #include <esp32-hal-log.h>   | ||||
| #include <esp32-hal-log.h> | ||||
| 
 | ||||
| // attn: increment version after modifications to configData_t truct!
 | ||||
| #define PROGVERSION "1.3.91" // use max 10 chars here!
 | ||||
| #define PROGVERSION "1.3.92" // use max 10 chars here!
 | ||||
| #define PROGNAME "PAXCNT" | ||||
| 
 | ||||
| // std::set for unified array functions
 | ||||
| @ -36,12 +36,12 @@ typedef struct { | ||||
|   char version[10];      // Firmware version
 | ||||
| } configData_t; | ||||
| 
 | ||||
| extern configData_t cfg; | ||||
| extern char display_line6[], display_line7[]; | ||||
| extern int countermode, screensaver, adrmode, lorasf, txpower, rlim; | ||||
| extern uint8_t channel, DisplayState; | ||||
| // global variables
 | ||||
| extern configData_t cfg;                      // current device configuration
 | ||||
| extern char display_line6[], display_line7[]; // screen buffers
 | ||||
| extern uint8_t channel;                       // wifi channel rotation counter
 | ||||
| extern uint16_t macs_total, macs_wifi, macs_ble; // MAC counters
 | ||||
| extern std::set<uint16_t> macs; | ||||
| extern std::set<uint16_t> macs;                  // temp storage for MACs
 | ||||
| extern hw_timer_t *channelSwitch, *sendCycle; | ||||
| extern portMUX_TYPE timerMux; | ||||
| 
 | ||||
| @ -49,6 +49,8 @@ extern portMUX_TYPE timerMux; | ||||
| #include "gps.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "payload.h" | ||||
| 
 | ||||
| #ifdef HAS_LORA | ||||
| #include "lorawan.h" | ||||
| #endif | ||||
| @ -69,18 +71,6 @@ extern portMUX_TYPE timerMux; | ||||
| #include "antenna.h" | ||||
| #endif | ||||
| 
 | ||||
| // class for preparing payload data
 | ||||
| #include "payload.h" | ||||
| #if PAYLOAD_ENCODER == 1 | ||||
| extern TTNplain payload; | ||||
| #elif PAYLOAD_ENCODER == 2 | ||||
| extern TTNpacked payload; | ||||
| #elif PAYLOAD_ENCODER == 3 | ||||
| extern CayenneLPP payload; | ||||
| #else | ||||
| #error "No valid payload converter defined" | ||||
| #endif | ||||
| 
 | ||||
| void reset_counters(void); | ||||
| void blink_LED(uint16_t set_color, uint16_t set_blinkduration); | ||||
| void led_loop(void); | ||||
|  | ||||
| @ -5,13 +5,16 @@ | ||||
| // Local logging tag
 | ||||
| static const char TAG[] = "main"; | ||||
| 
 | ||||
| TinyGPSPlus gps;         | ||||
| gpsStatus_t gps_status; | ||||
| 
 | ||||
| // read GPS data and cast to global struct
 | ||||
| void gps_read() { | ||||
|   gps_status.latitude = (uint32_t)(gps.location.lat() * 1e6); | ||||
|   gps_status.longitude = (uint32_t)(gps.location.lng() * 1e6); | ||||
|   gps_status.latitude = (int32_t)(gps.location.lat() * 1e6); | ||||
|   gps_status.longitude = (int32_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(); | ||||
|   gps_status.altitude = (int16_t)gps.altitude.meters(); | ||||
| } | ||||
| 
 | ||||
| // GPS serial feed FreeRTos Task
 | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #define CFG_sx1276_radio 1 // select LoRa chip
 | ||||
| //#define CFG_sx1272_radio 1 // select LoRa chip
 | ||||
| #define BOARD_HAS_PSRAM // use if board has external PSRAM
 | ||||
| #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
 | ||||
| 
 | ||||
| #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C | ||||
| //#define DISPLAY_FLIP  1 // use if display is rotated
 | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
| #define HAS_LORA  1       // comment out if device shall not send data via LoRa
 | ||||
| #define HAS_SPI   1       // comment out if device shall not send data via SPI
 | ||||
| #define CFG_sx1276_radio 1 // HPD13A LoRa SoC
 | ||||
| #define BOARD_HAS_PSRAM // use extra 4MB extern RAM
 | ||||
| 
 | ||||
| #define HAS_LED GPIO_NUM_21 // on board green LED_G1
 | ||||
| //#define HAS_BUTTON GPIO_NUM_39 // on board button "BOOT" (next to reset button) !! seems not to work!!
 | ||||
| #define BOARD_HAS_PSRAM // use extra 4MB extern RAM
 | ||||
| #define HAS_LED GPIO_NUM_21 // on board green LED
 | ||||
| 
 | ||||
| #define HAS_BUTTON GPIO_NUM_39 // on board button "BOOT" (next to reset button)
 | ||||
| 
 | ||||
| #define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
 | ||||
| #define BATT_FACTOR 2 // voltage divider 100k/100k on board
 | ||||
| #define HAS_GPS 1 // use on board GPS
 | ||||
|  | ||||
| @ -23,8 +23,6 @@ | ||||
|  * | ||||
|  ************************************************************/ | ||||
| 
 | ||||
| #include <Arduino.h> | ||||
| 
 | ||||
| static const u1_t DEVEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||||
| 
 | ||||
| static const u1_t APPEUI[8] = {0x70, 0xB3, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||||
|  | ||||
							
								
								
									
										32
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/main.cpp
									
									
									
									
									
								
							| @ -27,20 +27,14 @@ licenses. Refer to LICENSE.txt file in repository for more details. | ||||
| #include "globals.h" | ||||
| #include "main.h" | ||||
| 
 | ||||
| // Initialize global variables
 | ||||
| configData_t cfg; // struct holds current device configuration
 | ||||
| char display_line6[16], display_line7[16]; // display buffers
 | ||||
| uint8_t DisplayState = 0, channel = 0;     // globals for state machine
 | ||||
| uint8_t channel = 0;                       // channel rotation counter
 | ||||
| uint16_t macs_total = 0, macs_wifi = 0, | ||||
|          macs_ble = 0;      // MAC counters globals for display
 | ||||
|          macs_ble = 0; // MAC counters globals for display
 | ||||
| hw_timer_t *channelSwitch = NULL, *displaytimer = NULL, | ||||
|            *sendCycle = NULL; // configure hardware timer for cyclic tasks
 | ||||
| 
 | ||||
| #ifdef HAS_GPS | ||||
| gpsStatus_t gps_status; // struct for storing gps data
 | ||||
| TinyGPSPlus gps;        // create TinyGPS++ instance
 | ||||
| #endif | ||||
| 
 | ||||
| // this variables will be changed in the ISR, and read in main loop
 | ||||
| static volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, | ||||
|                     SendCycleTimerIRQ = 0, DisplayTimerIRQ = 0; | ||||
| @ -52,16 +46,8 @@ portMUX_TYPE timerMux = | ||||
| std::set<uint16_t> macs; // associative container holds total of unique MAC
 | ||||
|                          // adress hashes (Wifi + BLE)
 | ||||
| 
 | ||||
| // initialize payload encoder
 | ||||
| #if PAYLOAD_ENCODER == 1 | ||||
| TTNplain payload(PAYLOAD_BUFFER_SIZE); | ||||
| #elif PAYLOAD_ENCODER == 2 | ||||
| TTNpacked payload(PAYLOAD_BUFFER_SIZE); | ||||
| #elif PAYLOAD_ENCODER == 3 | ||||
| CayenneLPP payload(PAYLOAD_BUFFER_SIZE); | ||||
| #else | ||||
| #error "No valid payload converter defined" | ||||
| #endif | ||||
| // initialize payload ncoder
 | ||||
| PayloadConvert payload(PAYLOAD_BUFFER_SIZE); | ||||
| 
 | ||||
| // local Tag for logging
 | ||||
| static const char TAG[] = "main"; | ||||
| @ -153,9 +139,9 @@ void readButton() { | ||||
|     ButtonPressedIRQ = 0; | ||||
|     portEXIT_CRITICAL(&timerMux); | ||||
|     ESP_LOGI(TAG, "Button pressed"); | ||||
|     ESP_LOGI(TAG, "Button pressed, resetting device to factory defaults"); | ||||
|     eraseConfig(); | ||||
|     esp_restart(); | ||||
|     payload.reset(); | ||||
|     payload.addButton(0x01); | ||||
|     senddata(BUTTONPORT); | ||||
|   } | ||||
| } | ||||
| #endif | ||||
| @ -225,7 +211,7 @@ void sendPayload() { | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     senddata(PAYLOADPORT); | ||||
|     senddata(COUNTERPORT); | ||||
|   } | ||||
| } // sendPayload()
 | ||||
| 
 | ||||
| @ -456,7 +442,7 @@ void loop() { | ||||
|                "Memory full, counter cleared (heap low water mark = %d Bytes / " | ||||
|                "free heap = %d bytes)", | ||||
|                esp_get_minimum_free_heap_size(), ESP.getFreeHeap()); | ||||
|       senddata(PAYLOADPORT); // send data before clearing counters
 | ||||
|       senddata(COUNTERPORT); // send data before clearing counters
 | ||||
|       reset_counters();      // clear macs container and reset all counters
 | ||||
|       reset_salt();          // get new salt for salting hashes
 | ||||
|     } | ||||
|  | ||||
| @ -7,7 +7,11 @@ | ||||
| // Verbose enables serial output | ||||
| #define VERBOSE                         1       // comment out to silence the device, for mute use build option | ||||
| 
 | ||||
| // set this to include BLE counting and vendor filter functions | ||||
| // Payload send cycle and encoding | ||||
| #define SEND_SECS                       30      // payload send cycle [seconds/2] -> 240 sec. | ||||
| #define PAYLOAD_ENCODER                 3       // payload encoder: 1=Plain, 2=Packed, 3=CayenneLPP dynamic, 4=CayenneLPP packed | ||||
| 
 | ||||
| // Set this to include BLE counting and vendor filter functions | ||||
| #define VENDORFILTER                    1       // comment out if you want to count things, not people | ||||
| #define BLECOUNTER                      1       // comment out if you don't want BLE count, saves power & memory | ||||
| 
 | ||||
| @ -38,6 +42,7 @@ | ||||
| // LoRa payload default parameters | ||||
| #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 | ||||
| @ -45,11 +50,13 @@ | ||||
| #define MAXLORARETRY                    500     // maximum count of TX retries if LoRa busy | ||||
| 
 | ||||
| // Ports on which the device sends and listenes on LoRaWAN and SPI | ||||
| #define PAYLOADPORT                     1       // Port on which device sends counts | ||||
| #define COUNTERPORT                     1       // Port on which device sends counts | ||||
| #define RCMDPORT                        2       // Port on which device listenes for remote commands | ||||
| #define STATUSPORT                      2       // Port on which device sends remote command results | ||||
| #define CONFIGPORT                      3       // Port on which device sends gps query results | ||||
| #define GPSPORT                         4       // Port on which device sends gps query results | ||||
| #define BUTTONPORT                      5       // Port on which device sends button pressed signal | ||||
| #define CAYENNEPORT                     2       // Port for Cayenne LPP 2.0 packet sensor encoding | ||||
| 
 | ||||
| // Default RGB LED luminosity (in %) | ||||
| #define RGBLUMINOSITY                   30      // 30% | ||||
|  | ||||
							
								
								
									
										211
									
								
								src/payload.cpp
									
									
									
									
									
								
							
							
						
						
									
										211
									
								
								src/payload.cpp
									
									
									
									
									
								
							| @ -2,47 +2,31 @@ | ||||
| #include "globals.h" | ||||
| #include "payload.h" | ||||
| 
 | ||||
| /* ---------------- plain format without special encoding ---------- */ | ||||
| 
 | ||||
| TTNplain::TTNplain(uint8_t size) { | ||||
| PayloadConvert::PayloadConvert(uint8_t size) { | ||||
|   buffer = (uint8_t *)malloc(size); | ||||
|   cursor = 0; | ||||
| } | ||||
| 
 | ||||
| TTNplain::~TTNplain(void) { free(buffer); } | ||||
| PayloadConvert::~PayloadConvert(void) { free(buffer); } | ||||
| 
 | ||||
| void TTNplain::reset(void) { cursor = 0; } | ||||
| void PayloadConvert::reset(void) { cursor = 0; } | ||||
| 
 | ||||
| uint8_t TTNplain::getSize(void) { return cursor; } | ||||
| uint8_t PayloadConvert::getSize(void) { return cursor; } | ||||
| 
 | ||||
| uint8_t *TTNplain::getBuffer(void) { return buffer; } | ||||
| uint8_t *PayloadConvert::getBuffer(void) { return buffer; } | ||||
| 
 | ||||
| void TTNplain::addCount(uint16_t value1, uint16_t value2) { | ||||
| /* ---------------- plain format without special encoding ---------- */ | ||||
| 
 | ||||
| #if PAYLOAD_ENCODER == 1 | ||||
| 
 | ||||
| void PayloadConvert::addCount(uint16_t value1, uint16_t value2) { | ||||
|   buffer[cursor++] = value1 >> 8; | ||||
|   buffer[cursor++] = value1; | ||||
|   buffer[cursor++] = value2 >> 8; | ||||
|   buffer[cursor++] = value2; | ||||
| } | ||||
| 
 | ||||
| #ifdef HAS_GPS | ||||
| void TTNplain::addGPS(gpsStatus_t value) { | ||||
|   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; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void TTNplain::addConfig(configData_t value) { | ||||
| void PayloadConvert::addConfig(configData_t value) { | ||||
|   buffer[cursor++] = value.lorasf; | ||||
|   buffer[cursor++] = value.txpower; | ||||
|   buffer[cursor++] = value.adrmode; | ||||
| @ -63,7 +47,8 @@ void TTNplain::addConfig(configData_t value) { | ||||
|   cursor += 10; | ||||
| } | ||||
| 
 | ||||
| void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { | ||||
| void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, | ||||
|                                float cputemp) { | ||||
|   buffer[cursor++] = voltage >> 8; | ||||
|   buffer[cursor++] = voltage; | ||||
|   buffer[cursor++] = uptime >> 56; | ||||
| @ -80,38 +65,40 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { | ||||
|   buffer[cursor++] = (uint32_t)cputemp; | ||||
| } | ||||
| 
 | ||||
| #ifdef HAS_GPS | ||||
| void PayloadConvert::addGPS(gpsStatus_t value) { | ||||
|   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; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef HAS_BUTTON | ||||
| void PayloadConvert::addButton(uint8_t value) { buffer[cursor++] = value; } | ||||
| #endif | ||||
| 
 | ||||
| /* ---------------- packed format with LoRa serialization Encoder ---------- */ | ||||
| // derived from
 | ||||
| // https://github.com/thesolarnomad/lora-serialization/blob/master/src/LoraEncoder.cpp
 | ||||
| 
 | ||||
| TTNpacked::TTNpacked(uint8_t size) { | ||||
|   buffer = (uint8_t *)malloc(size); | ||||
|   cursor = 0; | ||||
| } | ||||
| #elif PAYLOAD_ENCODER == 2 | ||||
| 
 | ||||
| TTNpacked::~TTNpacked(void) { free(buffer); } | ||||
| 
 | ||||
| void TTNpacked::reset(void) { cursor = 0; } | ||||
| 
 | ||||
| uint8_t TTNpacked::getSize(void) { return cursor; } | ||||
| 
 | ||||
| uint8_t *TTNpacked::getBuffer(void) { return buffer; } | ||||
| 
 | ||||
| void TTNpacked::addCount(uint16_t value1, uint16_t value2) { | ||||
| void PayloadConvert::addCount(uint16_t value1, uint16_t value2) { | ||||
|   writeUint16(value1); | ||||
|   writeUint16(value2); | ||||
| } | ||||
| 
 | ||||
| #ifdef HAS_GPS | ||||
| void TTNpacked::addGPS(gpsStatus_t value) { | ||||
|   writeLatLng(value.latitude, value.longitude); | ||||
|   writeUint8(value.satellites); | ||||
|   writeUint16(value.hdop); | ||||
|   writeUint16(value.altitude); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void TTNpacked::addConfig(configData_t value) { | ||||
| void PayloadConvert::addConfig(configData_t value) { | ||||
|   writeUint8(value.lorasf); | ||||
|   writeUint8(value.txpower); | ||||
|   writeUint16(value.rssilimit); | ||||
| @ -125,33 +112,47 @@ void TTNpacked::addConfig(configData_t value) { | ||||
|               value.vendorfilter ? true : false, value.gpsmode ? true : false); | ||||
| } | ||||
| 
 | ||||
| void TTNpacked::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) { | ||||
| void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, | ||||
|                                float cputemp) { | ||||
|   writeUint16(voltage); | ||||
|   writeUptime(uptime); | ||||
|   writeTemperature(cputemp); | ||||
| } | ||||
| 
 | ||||
| void TTNpacked::intToBytes(uint8_t pos, int32_t i, uint8_t byteSize) { | ||||
| #ifdef HAS_GPS | ||||
| void PayloadConvert::addGPS(gpsStatus_t value) { | ||||
|   writeLatLng(value.latitude, value.longitude); | ||||
|   writeUint8(value.satellites); | ||||
|   writeUint16(value.hdop); | ||||
|   writeUint16(value.altitude); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef HAS_BUTTON | ||||
| void PayloadConvert::addButton(uint8_t value) { writeUint8(value); } | ||||
| #endif | ||||
| 
 | ||||
| void PayloadConvert::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::writeUptime(uint64_t uptime) { | ||||
| void PayloadConvert::writeUptime(uint64_t uptime) { | ||||
|   intToBytes(cursor, uptime, 8); | ||||
| } | ||||
| 
 | ||||
| void TTNpacked::writeLatLng(double latitude, double longitude) { | ||||
| void PayloadConvert::writeLatLng(double latitude, double longitude) { | ||||
|   intToBytes(cursor, latitude, 4); | ||||
|   intToBytes(cursor, longitude, 4); | ||||
| } | ||||
| 
 | ||||
| void TTNpacked::writeUint16(uint16_t i) { intToBytes(cursor, i, 2); } | ||||
| void PayloadConvert::writeUint16(uint16_t i) { intToBytes(cursor, i, 2); } | ||||
| 
 | ||||
| void TTNpacked::writeUint8(uint8_t i) { intToBytes(cursor, i, 1); } | ||||
| void PayloadConvert::writeUint8(uint8_t i) { intToBytes(cursor, i, 1); } | ||||
| 
 | ||||
| void TTNpacked::writeHumidity(float humidity) { | ||||
| void PayloadConvert::writeHumidity(float humidity) { | ||||
|   int16_t h = (int16_t)(humidity * 100); | ||||
|   intToBytes(cursor, h, 2); | ||||
| } | ||||
| @ -160,7 +161,7 @@ void TTNpacked::writeHumidity(float humidity) { | ||||
|  * Uses a 16bit two's complement with two decimals, so the range is | ||||
|  * -327.68 to +327.67 degrees | ||||
|  */ | ||||
| void TTNpacked::writeTemperature(float temperature) { | ||||
| void PayloadConvert::writeTemperature(float temperature) { | ||||
|   int16_t t = (int16_t)(temperature * 100); | ||||
|   if (temperature < 0) { | ||||
|     t = ~-t; | ||||
| @ -170,8 +171,8 @@ void TTNpacked::writeTemperature(float temperature) { | ||||
|   buffer[cursor++] = (byte)t & 0xFF; | ||||
| } | ||||
| 
 | ||||
| void TTNpacked::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, | ||||
|                             bool g, bool h) { | ||||
| void PayloadConvert::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; | ||||
| @ -186,37 +187,60 @@ void TTNpacked::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, | ||||
| } | ||||
| 
 | ||||
| /* ---------------- Cayenne LPP format ---------- */ | ||||
| // http://community.mydevices.com/t/cayenne-lpp-2-0/7510
 | ||||
| 
 | ||||
| CayenneLPP::CayenneLPP(uint8_t size) { | ||||
|   buffer = (uint8_t *)malloc(size); | ||||
|   cursor = 0; | ||||
| #elif (PAYLOAD_ENCODER == 3 || PAYLOAD_ENCODER == 4) | ||||
| 
 | ||||
| void PayloadConvert::addCount(uint16_t value1, uint16_t value2) { | ||||
|   uint16_t val1 = value1 * 100; | ||||
|   uint16_t val2 = value2 * 100; | ||||
| #if (PAYLOAD_ENCODER == 3) | ||||
|   buffer[cursor++] = LPP_COUNT_WIFI_CHANNEL; | ||||
| #endif | ||||
|   buffer[cursor++] = LPP_ANALOG_INPUT; // workaround, type meter not found?
 | ||||
|   buffer[cursor++] = val1 >> 8; | ||||
|   buffer[cursor++] = val1; | ||||
| #if (PAYLOAD_ENCODER == 3) | ||||
|   buffer[cursor++] = LPP_COUNT_BLE_CHANNEL; | ||||
| #endif | ||||
|   buffer[cursor++] = LPP_ANALOG_INPUT; // workaround, type meter not found?
 | ||||
|   buffer[cursor++] = val2 >> 8; | ||||
|   buffer[cursor++] = val2; | ||||
| } | ||||
| 
 | ||||
| CayenneLPP::~CayenneLPP(void) { free(buffer); } | ||||
| void PayloadConvert::addConfig(configData_t value) { | ||||
| #if (PAYLOAD_ENCODER == 3) | ||||
|   buffer[cursor++] = LPP_ADR_CHANNEL; | ||||
| #endif | ||||
|   buffer[cursor++] = LPP_DIGITAL_INPUT; | ||||
|   buffer[cursor++] = value.adrmode; | ||||
| } | ||||
| 
 | ||||
| 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; // workaround, type meter not found?
 | ||||
|   buffer[cursor++] = value1 >> 8; | ||||
|   buffer[cursor++] = value1; | ||||
|   buffer[cursor++] = LPP_COUNT_BLE_CHANNEL; | ||||
|   buffer[cursor++] = LPP_ANALOG_INPUT; // workaround, type meter not found?
 | ||||
|   buffer[cursor++] = value2 >> 8; | ||||
|   buffer[cursor++] = value2; | ||||
| void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, | ||||
|                                float celsius) { | ||||
|   int16_t val = celsius * 10; | ||||
| #if (PAYLOAD_ENCODER == 3) | ||||
|   buffer[cursor++] = LPP_BATT_CHANNEL; | ||||
| #endif | ||||
|   buffer[cursor++] = LPP_ANALOG_INPUT; | ||||
|   buffer[cursor++] = voltage >> 8; | ||||
|   buffer[cursor++] = voltage; | ||||
| #if (PAYLOAD_ENCODER == 3) | ||||
|   buffer[cursor++] = LPP_TEMP_CHANNEL; | ||||
| #endif | ||||
|   buffer[cursor++] = LPP_TEMPERATURE; | ||||
|   buffer[cursor++] = (uint16_t)val >> 8; | ||||
|   buffer[cursor++] = (uint16_t)val; | ||||
| } | ||||
| 
 | ||||
| #ifdef HAS_GPS | ||||
| void CayenneLPP::addGPS(gpsStatus_t value) { | ||||
| void PayloadConvert::addGPS(gpsStatus_t value) { | ||||
|   int32_t lat = value.latitude / 100; | ||||
|   int32_t lon = value.longitude / 100; | ||||
|   int32_t alt = value.altitude; | ||||
|   int32_t alt = value.altitude * 100; | ||||
| #if (PAYLOAD_ENCODER == 3) | ||||
|   buffer[cursor++] = LPP_GPS_CHANNEL; | ||||
| #endif | ||||
|   buffer[cursor++] = LPP_GPS; | ||||
|   buffer[cursor++] = lat >> 16; | ||||
|   buffer[cursor++] = lat >> 8; | ||||
| @ -230,19 +254,16 @@ void CayenneLPP::addGPS(gpsStatus_t value) { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void CayenneLPP::addConfig(configData_t value) { | ||||
|   buffer[cursor++] = LPP_ADR_CHANNEL; | ||||
| #ifdef HAS_BUTTON | ||||
| void PayloadConvert::addButton(uint8_t value) { | ||||
| #if (PAYLOAD_ENCODER == 3) | ||||
|   buffer[cursor++] = LPP_BUTTON_CHANNEL; | ||||
| #endif | ||||
|   buffer[cursor++] = LPP_DIGITAL_INPUT; | ||||
|   buffer[cursor++] = value.adrmode; | ||||
|   buffer[cursor++] = value; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| #else | ||||
| #error "No valid payload converter defined" | ||||
| #endif | ||||
| @ -1,13 +1,18 @@ | ||||
| #ifndef _PAYLOAD_H_ | ||||
| #define _PAYLOAD_H_ | ||||
| 
 | ||||
| // MyDevices CayenneLPP channels
 | ||||
| // MyDevices CayenneLPP channels for dynamic sensor payload format
 | ||||
| #if (PAYLOAD_ENCODER == 3) | ||||
| 
 | ||||
| #define LPP_GPS_CHANNEL 20 | ||||
| #define LPP_COUNT_WIFI_CHANNEL 21 | ||||
| #define LPP_COUNT_BLE_CHANNEL 22 | ||||
| #define LPP_BATT_CHANNEL 23 | ||||
| #define LPP_BUTTON_CHANNEL 24 | ||||
| #define LPP_ADR_CHANNEL 25 | ||||
| #define LPP_TEMP_CHANNEL 26 | ||||
| #endif | ||||
| 
 | ||||
| // 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
 | ||||
| @ -16,42 +21,34 @@ | ||||
| #define LPP_ANALOG_INPUT 2   // 2 bytes, 0.01 signed
 | ||||
| #define LPP_LUMINOSITY 101   // 2 bytes, 1 lux unsigned
 | ||||
| 
 | ||||
| class TTNplain { | ||||
| class PayloadConvert { | ||||
| 
 | ||||
| public: | ||||
|   TTNplain(uint8_t size); | ||||
|   ~TTNplain(); | ||||
|   PayloadConvert(uint8_t size); | ||||
|   ~PayloadConvert(); | ||||
| 
 | ||||
|   void reset(void); | ||||
|   uint8_t getSize(void); | ||||
|   uint8_t *getBuffer(void); | ||||
| 
 | ||||
|   void addCount(uint16_t value1, uint16_t value2); | ||||
|   void addConfig(configData_t value); | ||||
|   void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); | ||||
| #ifdef HAS_GPS | ||||
|   void addGPS(gpsStatus_t value); | ||||
| #endif | ||||
| #ifdef HAS_BUTTON | ||||
|   void addButton(uint8_t value); | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| #if PAYLOAD_ENCODER == 1 // format plain
 | ||||
| 
 | ||||
| private: | ||||
|   uint8_t *buffer; | ||||
|   uint8_t cursor; | ||||
| }; | ||||
| 
 | ||||
| class TTNpacked { | ||||
| public: | ||||
|   TTNpacked(uint8_t size); | ||||
|   ~TTNpacked(); | ||||
| 
 | ||||
|   void reset(void); | ||||
|   uint8_t getSize(void); | ||||
|   uint8_t *getBuffer(void); | ||||
| 
 | ||||
|   void addCount(uint16_t value1, uint16_t value2); | ||||
|   void addConfig(configData_t value); | ||||
|   void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); | ||||
| #ifdef HAS_GPS | ||||
|   void addGPS(gpsStatus_t value); | ||||
| #endif | ||||
| #elif PAYLOAD_ENCODER == 2 // format packed
 | ||||
| 
 | ||||
| private: | ||||
|   uint8_t *buffer; | ||||
| @ -67,21 +64,7 @@ private: | ||||
|                    bool h); | ||||
| }; | ||||
| 
 | ||||
| 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 addConfig(configData_t value); | ||||
|   void addStatus(uint16_t voltage, uint64_t uptime, float cputemp); | ||||
| #ifdef HAS_GPS | ||||
|   void addGPS(gpsStatus_t value); | ||||
| #endif | ||||
| #elif (PAYLOAD_ENCODER == 3 || PAYLOAD_ENCODER == 4) // format cayenne lpp
 | ||||
| 
 | ||||
| private: | ||||
|   uint8_t *buffer; | ||||
| @ -89,4 +72,10 @@ private: | ||||
|   uint8_t cursor; | ||||
| }; | ||||
| 
 | ||||
| #endif // _PAYLOAD_H_
 | ||||
| #else | ||||
| #error "No valid payload converter defined" | ||||
| #endif | ||||
| 
 | ||||
| extern PayloadConvert payload; | ||||
| 
 | ||||
| #endif // _PAYLOAD_H_
 | ||||
| @ -9,9 +9,10 @@ void senddata(uint8_t port) { | ||||
|     ESP_LOGI(TAG, "LoRa busy, data not sent"); | ||||
|     sprintf(display_line7, "LORA BUSY"); | ||||
|   } else { | ||||
|     // send payload via LoRa
 | ||||
|     LMIC_setTxData2(port, payload.getBuffer(), payload.getSize(), | ||||
|     LMIC_setTxData2(PAYLOAD_ENCODER == 4 ? CAYENNEPORT : port, | ||||
|                     payload.getBuffer(), payload.getSize(), | ||||
|                     (cfg.countermode & 0x02)); | ||||
| 
 | ||||
|     ESP_LOGI(TAG, "%d bytes queued to send on LoRa", payload.getSize()); | ||||
|     sprintf(display_line7, "PACKET QUEUED"); | ||||
|   } | ||||
| @ -23,10 +24,10 @@ void senddata(uint8_t port) { | ||||
| #endif | ||||
| 
 | ||||
|   // clear counter if not in cumulative counter mode
 | ||||
|   if ((port == PAYLOADPORT) && (cfg.countermode != 1)) { | ||||
|   if ((port == COUNTERPORT) && (cfg.countermode != 1)) { | ||||
|     reset_counters(); // clear macs container and reset all counters
 | ||||
|     reset_salt();     // get new salt for salting hashes
 | ||||
|     ESP_LOGI(TAG, "Counter cleared (countermode = %d)", cfg.countermode); | ||||
|     ESP_LOGI(TAG, "Counter cleared"); | ||||
|   } | ||||
| 
 | ||||
| } // senddata
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user