2018-06-10 22:46:13 +02:00
|
|
|
/*
|
2018-07-15 19:41:22 +02:00
|
|
|
|
|
|
|
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
|
2018-06-10 22:46:13 +02:00
|
|
|
|
|
|
|
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
|
|
|
|
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
|
|
|
|
NOTICE:
|
|
|
|
Parts of the source files in this repository are made available under different
|
|
|
|
licenses. Refer to LICENSE.txt file in repository for more details.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Basic Config
|
|
|
|
#include "globals.h"
|
2018-07-17 11:53:43 +02:00
|
|
|
#include "main.h"
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-07-14 20:07:33 +02:00
|
|
|
configData_t cfg; // struct holds current device configuration
|
|
|
|
char display_line6[16], display_line7[16]; // display buffers
|
2018-07-19 21:53:56 +02:00
|
|
|
uint8_t channel = 0; // channel rotation counter
|
2018-07-22 08:41:41 +02:00
|
|
|
uint16_t macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
|
|
|
batt_voltage = 0; // globals for display
|
|
|
|
|
|
|
|
// hardware timer for cyclic tasks
|
|
|
|
hw_timer_t *channelSwitch = NULL, *displaytimer = NULL, *sendCycle = NULL,
|
2018-07-22 20:27:58 +02:00
|
|
|
*homeCycle = NULL;
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-07-15 14:28:05 +02:00
|
|
|
// this variables will be changed in the ISR, and read in main loop
|
2018-07-22 20:27:58 +02:00
|
|
|
volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, SendCycleTimerIRQ = 0,
|
|
|
|
DisplayTimerIRQ = 0, HomeCycleIRQ = 0;
|
2018-07-15 14:28:05 +02:00
|
|
|
|
2018-06-10 22:46:13 +02:00
|
|
|
portMUX_TYPE timerMux =
|
|
|
|
portMUX_INITIALIZER_UNLOCKED; // sync main loop and ISR when modifying IRQ
|
|
|
|
// handler shared variables
|
|
|
|
|
2018-07-24 18:44:13 +02:00
|
|
|
std::set<uint16_t> macs; // associative container holding unique MAC
|
2018-07-31 00:00:24 +02:00
|
|
|
// adress hashes (Wifi + BLE)
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-07-24 18:44:13 +02:00
|
|
|
// initialize payload encoder
|
2018-07-19 22:33:37 +02:00
|
|
|
PayloadConvert payload(PAYLOAD_BUFFER_SIZE);
|
2018-06-16 19:50:36 +02:00
|
|
|
|
2018-06-10 22:46:13 +02:00
|
|
|
// local Tag for logging
|
|
|
|
static const char TAG[] = "main";
|
|
|
|
|
|
|
|
/* begin Aruino SETUP
|
|
|
|
* ------------------------------------------------------------ */
|
|
|
|
|
|
|
|
void setup() {
|
2018-06-17 11:40:52 +02:00
|
|
|
|
2018-08-02 11:33:02 +02:00
|
|
|
char features[100] = "";
|
2018-06-10 22:46:13 +02:00
|
|
|
|
|
|
|
// disable brownout detection
|
|
|
|
#ifdef DISABLE_BROWNOUT
|
|
|
|
// register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
|
|
|
|
(*((volatile uint32_t *)ETS_UNCACHED_ADDR((DR_REG_RTCCNTL_BASE + 0xd4)))) = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// setup debug output or silence device
|
|
|
|
#ifdef VERBOSE
|
|
|
|
Serial.begin(115200);
|
|
|
|
esp_log_level_set("*", ESP_LOG_VERBOSE);
|
|
|
|
#else
|
|
|
|
// mute logs completely by redirecting them to silence function
|
|
|
|
esp_log_level_set("*", ESP_LOG_NONE);
|
|
|
|
esp_log_set_vprintf(redirect_log);
|
|
|
|
#endif
|
|
|
|
|
2018-07-08 12:59:49 +02:00
|
|
|
ESP_LOGI(TAG, "Starting %s v%s", PROGNAME, PROGVERSION);
|
2018-06-10 22:46:13 +02:00
|
|
|
|
|
|
|
// initialize system event handler for wifi task, needed for
|
|
|
|
// wifi_sniffer_init()
|
|
|
|
esp_event_loop_init(NULL, NULL);
|
|
|
|
|
|
|
|
// print chip information on startup if in verbose mode
|
|
|
|
#ifdef VERBOSE
|
|
|
|
esp_chip_info_t chip_info;
|
|
|
|
esp_chip_info(&chip_info);
|
|
|
|
ESP_LOGI(TAG,
|
|
|
|
"This is ESP32 chip with %d CPU cores, WiFi%s%s, silicon revision "
|
|
|
|
"%d, %dMB %s Flash",
|
|
|
|
chip_info.cores, (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
|
|
|
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
|
|
|
|
chip_info.revision, spi_flash_get_chip_size() / (1024 * 1024),
|
|
|
|
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded"
|
|
|
|
: "external");
|
|
|
|
ESP_LOGI(TAG, "ESP32 SDK: %s", ESP.getSdkVersion());
|
2018-07-08 12:57:13 +02:00
|
|
|
ESP_LOGI(TAG, "Free RAM: %d bytes", ESP.getFreeHeap());
|
2018-06-10 22:46:13 +02:00
|
|
|
|
|
|
|
#ifdef HAS_GPS
|
2018-07-08 12:59:49 +02:00
|
|
|
ESP_LOGI(TAG, "TinyGPS+ v%s", TinyGPSPlus::libraryVersion());
|
2018-06-10 22:46:13 +02:00
|
|
|
#endif
|
|
|
|
|
2018-07-08 12:57:13 +02:00
|
|
|
#endif // verbose
|
|
|
|
|
2018-06-10 22:46:13 +02:00
|
|
|
// read settings from NVRAM
|
|
|
|
loadConfig(); // includes initialize if necessary
|
|
|
|
|
2018-08-02 11:33:02 +02:00
|
|
|
#ifdef VENDORFILTER
|
|
|
|
strcat_P(features, " OUIFLT");
|
|
|
|
#endif
|
|
|
|
|
2018-07-23 13:20:06 +02:00
|
|
|
// initialize LoRa
|
2018-08-02 11:33:02 +02:00
|
|
|
#ifdef HAS_LORA
|
2018-07-23 17:38:33 +02:00
|
|
|
strcat_P(features, " LORA");
|
2018-07-23 13:20:06 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// initialize led
|
2018-06-10 22:46:13 +02:00
|
|
|
#if (HAS_LED != NOT_A_PIN)
|
|
|
|
pinMode(HAS_LED, OUTPUT);
|
2018-06-17 11:40:52 +02:00
|
|
|
strcat_P(features, " LED");
|
2018-06-10 22:46:13 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAS_RGB_LED
|
|
|
|
rgb_set_color(COLOR_PINK);
|
2018-06-17 11:40:52 +02:00
|
|
|
strcat_P(features, " RGB");
|
2018-06-10 22:46:13 +02:00
|
|
|
#endif
|
|
|
|
|
2018-07-23 13:20:06 +02:00
|
|
|
// initialize button
|
2018-06-10 22:46:13 +02:00
|
|
|
#ifdef HAS_BUTTON
|
2018-06-17 11:40:52 +02:00
|
|
|
strcat_P(features, " BTN_");
|
2018-06-10 22:46:13 +02:00
|
|
|
#ifdef BUTTON_PULLUP
|
2018-06-17 11:40:52 +02:00
|
|
|
strcat_P(features, "PU");
|
2018-06-10 22:46:13 +02:00
|
|
|
// install button interrupt (pullup mode)
|
|
|
|
pinMode(HAS_BUTTON, INPUT_PULLUP);
|
|
|
|
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
|
|
|
|
#else
|
2018-06-17 11:40:52 +02:00
|
|
|
strcat_P(features, "PD");
|
2018-06-10 22:46:13 +02:00
|
|
|
// install button interrupt (pulldown mode)
|
|
|
|
pinMode(HAS_BUTTON, INPUT_PULLDOWN);
|
|
|
|
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING);
|
2018-07-14 20:31:46 +02:00
|
|
|
#endif // BUTTON_PULLUP
|
|
|
|
#endif // HAS_BUTTON
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-07-23 13:20:06 +02:00
|
|
|
// initialize wifi antenna
|
2018-06-10 22:46:13 +02:00
|
|
|
#ifdef HAS_ANTENNA_SWITCH
|
2018-06-17 11:40:52 +02:00
|
|
|
strcat_P(features, " ANT");
|
2018-06-10 22:46:13 +02:00
|
|
|
antenna_init();
|
2018-07-15 14:28:05 +02:00
|
|
|
antenna_select(cfg.wifiant);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// switch off bluetooth on esp32 module, if not compiled
|
|
|
|
#ifdef BLECOUNTER
|
|
|
|
strcat_P(features, " BLE");
|
|
|
|
#else
|
|
|
|
bool btstop = btStop();
|
2018-06-10 22:46:13 +02:00
|
|
|
#endif
|
|
|
|
|
2018-07-23 13:20:06 +02:00
|
|
|
// initialize gps
|
2018-06-10 22:46:13 +02:00
|
|
|
#ifdef HAS_GPS
|
2018-06-17 11:40:52 +02:00
|
|
|
strcat_P(features, " GPS");
|
2018-06-10 22:46:13 +02:00
|
|
|
#endif
|
|
|
|
|
2018-07-23 13:20:06 +02:00
|
|
|
// initialize battery status
|
2018-07-22 08:41:41 +02:00
|
|
|
#ifdef HAS_BATTERY_PROBE
|
|
|
|
strcat_P(features, " BATT");
|
2018-07-22 11:08:55 +02:00
|
|
|
calibrate_voltage();
|
2018-07-22 08:41:41 +02:00
|
|
|
batt_voltage = read_voltage();
|
|
|
|
#endif
|
|
|
|
|
2018-07-23 13:20:06 +02:00
|
|
|
// initialize display
|
2018-06-10 22:46:13 +02:00
|
|
|
#ifdef HAS_DISPLAY
|
2018-06-17 11:40:52 +02:00
|
|
|
strcat_P(features, " OLED");
|
2018-06-10 22:46:13 +02:00
|
|
|
DisplayState = cfg.screenon;
|
2018-07-15 14:28:05 +02:00
|
|
|
init_display(PROGNAME, PROGVERSION);
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-07-15 14:28:05 +02:00
|
|
|
// setup display refresh trigger IRQ using esp32 hardware timer
|
2018-06-10 22:46:13 +02:00
|
|
|
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
|
2018-07-15 20:05:05 +02:00
|
|
|
|
|
|
|
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up
|
|
|
|
displaytimer = timerBegin(0, 80, true);
|
|
|
|
// interrupt handler DisplayIRQ, triggered by edge
|
|
|
|
timerAttachInterrupt(displaytimer, &DisplayIRQ, true);
|
|
|
|
// reload interrupt after each trigger of display refresh cycle
|
|
|
|
timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true);
|
|
|
|
// enable display interrupt
|
|
|
|
timerAlarmEnable(displaytimer);
|
2018-06-10 22:46:13 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// setup channel rotation trigger IRQ using esp32 hardware timer 1
|
2018-07-14 23:13:25 +02:00
|
|
|
channelSwitch = timerBegin(1, 800, true);
|
2018-06-10 22:46:13 +02:00
|
|
|
timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true);
|
2018-07-14 23:13:25 +02:00
|
|
|
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 1000, true);
|
2018-06-10 22:46:13 +02:00
|
|
|
timerAlarmEnable(channelSwitch);
|
|
|
|
|
2018-07-14 23:13:25 +02:00
|
|
|
// setup send cycle trigger IRQ using esp32 hardware timer 2
|
|
|
|
sendCycle = timerBegin(2, 8000, true);
|
|
|
|
timerAttachInterrupt(sendCycle, &SendCycleIRQ, true);
|
|
|
|
timerAlarmWrite(sendCycle, cfg.sendcycle * 2 * 10000, true);
|
|
|
|
timerAlarmEnable(sendCycle);
|
|
|
|
|
2018-07-22 20:27:58 +02:00
|
|
|
// setup house keeping cycle trigger IRQ using esp32 hardware timer 3
|
|
|
|
homeCycle = timerBegin(3, 8000, true);
|
|
|
|
timerAttachInterrupt(homeCycle, &homeCycleIRQ, true);
|
|
|
|
timerAlarmWrite(homeCycle, HOMECYCLE * 10000, true);
|
|
|
|
timerAlarmEnable(homeCycle);
|
2018-07-22 08:41:41 +02:00
|
|
|
|
2018-06-17 11:40:52 +02:00
|
|
|
// show payload encoder
|
|
|
|
#if PAYLOAD_ENCODER == 1
|
2018-08-02 11:33:02 +02:00
|
|
|
strcat_P(features, " PLAIN");
|
2018-06-17 11:40:52 +02:00
|
|
|
#elif PAYLOAD_ENCODER == 2
|
2018-08-02 11:33:02 +02:00
|
|
|
strcat_P(features, " PACKED");
|
2018-06-17 11:40:52 +02:00
|
|
|
#elif PAYLOAD_ENCODER == 3
|
2018-08-02 11:33:02 +02:00
|
|
|
strcat_P(features, " LPPDYN");
|
2018-07-22 16:12:46 +02:00
|
|
|
#elif PAYLOAD_ENCODER == 4
|
2018-08-02 11:33:02 +02:00
|
|
|
strcat_P(features, " LPPPKD");
|
2018-06-17 11:40:52 +02:00
|
|
|
#endif
|
|
|
|
|
2018-06-10 22:46:13 +02:00
|
|
|
// show compiled features
|
2018-07-23 17:38:33 +02:00
|
|
|
ESP_LOGI(TAG, "Features:%s", features);
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-07-14 20:07:33 +02:00
|
|
|
#ifdef HAS_LORA
|
|
|
|
// output LoRaWAN keys to console
|
2018-06-10 22:46:13 +02:00
|
|
|
#ifdef VERBOSE
|
|
|
|
printKeys();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// initialize LoRaWAN LMIC run-time environment
|
|
|
|
os_init();
|
|
|
|
// reset LMIC MAC state
|
|
|
|
LMIC_reset();
|
|
|
|
// This tells LMIC to make the receive windows bigger, in case your clock is
|
|
|
|
// 1% faster or slower.
|
|
|
|
LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
|
2018-07-14 23:13:25 +02:00
|
|
|
// join network
|
|
|
|
LMIC_startJoining();
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-07-15 19:56:21 +02:00
|
|
|
// start lmic runloop in rtos task on core 1
|
|
|
|
// (note: arduino main loop runs on core 1, too)
|
2018-06-10 22:46:13 +02:00
|
|
|
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Starting Lora task on core 1");
|
2018-07-15 14:28:05 +02:00
|
|
|
xTaskCreatePinnedToCore(lorawan_loop, "loraloop", 2048, (void *)1,
|
2018-06-10 22:46:13 +02:00
|
|
|
(5 | portPRIVILEGE_BIT), NULL, 1);
|
2018-07-14 20:07:33 +02:00
|
|
|
#endif
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-07-15 14:28:05 +02:00
|
|
|
// if device has GPS and it is enabled, start GPS reader task on core 0 with
|
|
|
|
// higher priority than wifi channel rotation task since we process serial
|
|
|
|
// streaming NMEA data
|
|
|
|
#ifdef HAS_GPS
|
|
|
|
if (cfg.gpsmode) {
|
|
|
|
ESP_LOGI(TAG, "Starting GPS task on core 0");
|
|
|
|
xTaskCreatePinnedToCore(gps_loop, "gpsloop", 2048, (void *)1, 2, NULL, 0);
|
|
|
|
}
|
|
|
|
#endif
|
2018-06-10 22:46:13 +02:00
|
|
|
|
|
|
|
// start BLE scan callback if BLE function is enabled in NVRAM configuration
|
|
|
|
#ifdef BLECOUNTER
|
|
|
|
if (cfg.blescan) {
|
2018-07-15 14:28:05 +02:00
|
|
|
ESP_LOGI(TAG, "Starting BLE task on core 1");
|
2018-06-10 22:46:13 +02:00
|
|
|
start_BLEscan();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-07-15 14:28:05 +02:00
|
|
|
// start wifi in monitor mode and start channel rotation task on core 0
|
|
|
|
ESP_LOGI(TAG, "Starting Wifi task on core 0");
|
|
|
|
wifi_sniffer_init();
|
|
|
|
// initialize salt value using esp_random() called by random() in
|
2018-08-02 11:33:02 +02:00
|
|
|
// arduino-esp32 core. Note: do this *after* wifi has started, since function
|
2018-07-15 14:28:05 +02:00
|
|
|
// gets it's seed from RF noise
|
|
|
|
reset_salt(); // get new 16bit for salting hashes
|
|
|
|
xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1,
|
|
|
|
NULL, 0);
|
2018-08-02 11:33:02 +02:00
|
|
|
} // setup()
|
2018-06-10 22:46:13 +02:00
|
|
|
|
|
|
|
/* end Arduino SETUP
|
|
|
|
* ------------------------------------------------------------ */
|
|
|
|
|
|
|
|
/* begin Arduino main loop
|
|
|
|
* ------------------------------------------------------ */
|
|
|
|
|
|
|
|
void loop() {
|
|
|
|
|
|
|
|
while (1) {
|
2018-07-23 13:20:06 +02:00
|
|
|
// state machine for switching display, LED, button, housekeeping, senddata
|
2018-06-10 22:46:13 +02:00
|
|
|
|
|
|
|
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
|
|
|
led_loop();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAS_BUTTON
|
|
|
|
readButton();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAS_DISPLAY
|
|
|
|
updateDisplay();
|
|
|
|
#endif
|
|
|
|
|
2018-08-02 11:33:02 +02:00
|
|
|
// check housekeeping cycle and if expired do homework
|
2018-07-22 20:27:58 +02:00
|
|
|
checkHousekeeping();
|
2018-07-14 23:13:25 +02:00
|
|
|
// check send cycle and send payload if cycle is expired
|
2018-07-15 14:28:05 +02:00
|
|
|
sendPayload();
|
2018-08-02 11:33:02 +02:00
|
|
|
// reset watchdog
|
|
|
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
2018-06-10 22:46:13 +02:00
|
|
|
|
2018-08-02 11:33:02 +02:00
|
|
|
} // loop()
|
2018-06-10 22:46:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* end Arduino main loop
|
|
|
|
* ------------------------------------------------------------ */
|