Merge branch 'master' of https://github.com/cyberman54/ESP32-Paxcounter
This commit is contained in:
commit
3d931a1459
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@
|
||||
.clang_complete
|
||||
.gcc-flags.json
|
||||
src/loraconf.h
|
||||
src/ota.conf
|
4
LICENSE
4
LICENSE
@ -20,9 +20,9 @@ Parts of the source files in this repository are made available under different
|
||||
listed below. Refer to each individual source file for more details.
|
||||
|
||||
------------------------------------------------------------------------------------------------
|
||||
wifisniffer.cpp
|
||||
wifiscan.cpp
|
||||
|
||||
Parts of wifisniffer.cpp were derived or taken from
|
||||
Prior art was used for wifiscan.cpp and taken from
|
||||
|
||||
* Copyright (c) 2017, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
|
||||
* ESP32/016 WiFi Sniffer
|
||||
|
73
README.md
73
README.md
@ -31,8 +31,9 @@ This can all be done with a single small and cheap ESP32 board for less than $20
|
||||
- Pycom: LoPy, LoPy4, FiPy
|
||||
- WeMos: LoLin32 + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora),
|
||||
LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora)
|
||||
- Adafruit ESP32 Feather + LoRa Wing + OLED Wing, #IoT Octopus32 (Octopus + ESP32 Feather)
|
||||
|
||||
*SPI only*: (coming soon)
|
||||
*SPI only*: (code yet to come)
|
||||
|
||||
- Pyom: WiPy
|
||||
- WeMos: LoLin32, LoLin32 Lite, WeMos D32
|
||||
@ -44,10 +45,10 @@ Depending on board hardware following features are supported:
|
||||
- Button
|
||||
- Silicon unique ID
|
||||
- Battery voltage monitoring
|
||||
- GPS
|
||||
- GPS (Generic serial NMEA, or Quectel L76 I2C)
|
||||
|
||||
Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).<br>
|
||||
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory.<br>
|
||||
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory. If you want to use a ESP32 board which is not yet supported, use hal file generic.h and tailor pin mappings to your needs. Pull requests for new boards welcome.<br>
|
||||
|
||||
<b>3D printable cases</b> can be found (and, if wanted so, ordered) on Thingiverse, see
|
||||
<A HREF="https://www.thingiverse.com/thing:2670713">Heltec</A>, <A HREF="https://www.thingiverse.com/thing:2811127">TTGOv2</A>, <A HREF="https://www.thingiverse.com/thing:3005574">TTGOv2.1</A>, <A HREF="https://www.thingiverse.com/thing:3041339">T-BEAM</A> for example.<br>
|
||||
@ -62,6 +63,8 @@ Before compiling the code,
|
||||
|
||||
- **create file loraconf.h in your local /src directory** using the template [loraconf.sample.h](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/loraconf.sample.h) and populate it with your personal APPEUI und APPKEY for the LoRaWAN network. If you're using popular <A HREF="https://thethingsnetwork.org">TheThingsNetwork</A> you can copy&paste the keys from TTN console or output of ttnctl.
|
||||
|
||||
- **create file ota.conf in your local /src directory** using the template [ota.sample.conf](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/ota.sample.conf) and enter your WIFI network&key. These settings are used for downloading updates. If you want to push own OTA updates you need a <A HREF="https://bintray.com/JFrog">Bintray account</A>. Enter your Bintray user account data in ota.conf. If you don't need wireless firmware updates just rename ota.sample.conf to ota.conf.
|
||||
|
||||
To join the network only method OTAA is supported, not ABP. The DEVEUI for OTAA will be derived from the device's MAC adress during device startup and is shown as well on the device's display (if it has one) as on the serial console for copying it to your LoRaWAN network server settings.
|
||||
|
||||
If your device has a fixed DEVEUI enter this in your local loraconf.h file. During compile time this DEVEUI will be grabbed from loraconf.h and inserted in the code.
|
||||
@ -74,10 +77,14 @@ Use <A HREF="https://platformio.org/">PlatformIO</A> with your preferred IDE for
|
||||
|
||||
# Uploading
|
||||
|
||||
To upload the code to your ESP32 board this needs to be switched from run to bootloader mode. Boards with USB bridge like Heltec and TTGO usually have an onboard logic which allows soft switching by the upload tool. In PlatformIO this happenes automatically.<p>
|
||||
- **Initially, using USB/UART cable:**
|
||||
To upload the code via cable to your ESP32 board this needs to be switched from run to bootloader mode. Boards with USB bridge like Heltec and TTGO usually have an onboard logic which allows soft switching by the upload tool. In PlatformIO this happenes automatically.<p>
|
||||
The LoPy/LoPy4/FiPy board needs to be set manually. See these
|
||||
<A HREF="https://www.thethingsnetwork.org/labs/story/program-your-lopy-from-the-arduino-ide-using-lmic">instructions</A> how to do it. Don't forget to press on board reset button after switching between run and bootloader mode.<p>
|
||||
The original Pycom firmware is not needed, so there is no need to update it before flashing Paxcounter. Just flash the compiled paxcounter binary (.elf file) on your LoPy/LoPy4/FiPy. If you later want to go back to the Pycom firmware, download the firmware from Pycom and flash it over.
|
||||
|
||||
- **During runtime, using FOTA via WIFI:**
|
||||
After the ESP32 board is initially flashed and has joined a LoRaWAN network, the firmware can update itself by FOTA. This process is kicked off by sending a remote control command (see below) via LoRaWAN to the board. The board then tries to connect via WIFI to a cloud service (JFrog Bintray), checks for update, and if available downloads the binary and reboots with it. If something goes wrong during this process, the board reboots back to the current version. Prerequisites for FOTA are: 1. You own a Bintray repository, 2. you pushed the update binary to the Bintray repository, 3. internet access via encrypted (WPA2) WIFI is present at the board's site, 4. WIFI credentials were set in ota.conf and initially flashed to the board. Step 2 runs automated, just enter the credentials in ota.conf and set `upload_protocol = custom` in platformio.ini. Then press build and lean back watching platformio doing build and upload.
|
||||
|
||||
# Legal note
|
||||
|
||||
@ -128,7 +135,13 @@ If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) (TTN) you
|
||||
|
||||
To track a paxcounter device with on board GPS 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. The formats *plain* and *packed* generate the fields `latitude`, `longitude` and `hdop` required by ttnmapper.
|
||||
|
||||
Hereafter described is the default *plain* format, which uses MSB bit numbering.
|
||||
Hereafter described is the default *plain* format, which uses MSB bit numbering. Under /TTN in this repository you find some ready-to-go decoders which you may copy to your TTN console:
|
||||
|
||||
[**plain_decoder.js**](src/TTN/plain_decoder.js) |
|
||||
[**plain_converter.js**](src/TTN/plain_converter.js) |
|
||||
[**packed_decoder.js**](src/TTN/packed_decoder.js) |
|
||||
[**packed_converter.js**](src/TTN/packed_converter.js)
|
||||
|
||||
|
||||
**Port #1:** Paxcount data
|
||||
|
||||
@ -142,6 +155,7 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering.
|
||||
byte 3-10: Uptime [seconds]
|
||||
byte 11: CPU temperature [°C]
|
||||
bytes 12-15: Free RAM [bytes]
|
||||
bytes 16-17: Last CPU reset reason [core 0, core 1]
|
||||
|
||||
**Port #3:** Device configuration query result
|
||||
|
||||
@ -181,55 +195,11 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering.
|
||||
byte 1: Beacon RSSI reception level
|
||||
byte 2: Beacon identifier (0..255)
|
||||
|
||||
|
||||
[**plain_decoder.js**](src/TTN/plain_decoder.js)
|
||||
|
||||
```javascript
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
[**plain_converter.js**](src/TTN/plain_converter.js)
|
||||
|
||||
```javascript
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
# Remote control
|
||||
|
||||
The device listenes for remote control commands on LoRaWAN Port 2. Multiple commands per downlink are possible by concatenating them.
|
||||
|
||||
Note: all settings are stored in NVRAM and will be reloaded when device starts. To reset device to factory settings send remote command 09 02 09 00 unconfirmed(!) once.
|
||||
Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
||||
|
||||
0x01 set scan RSSI limit
|
||||
|
||||
@ -272,12 +242,13 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
||||
|
||||
useful to clear pending commands from LoRaWAN server quere, or to check RSSI on device
|
||||
|
||||
0x09 reset functions
|
||||
0x09 reset functions (send this command with confirmed ack only to avoid boot loops!)
|
||||
|
||||
0 = restart device
|
||||
1 = reset MAC counter to zero
|
||||
2 = reset device to factory settings
|
||||
3 = flush send queues
|
||||
9 = reboot device to OTA update via Wifi mode
|
||||
|
||||
0x0A set LoRaWAN payload send cycle
|
||||
|
||||
|
93
build.py
Normal file
93
build.py
Normal file
@ -0,0 +1,93 @@
|
||||
# build.py
|
||||
# pre-build script, setting up build environment
|
||||
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
import requests
|
||||
from os.path import basename
|
||||
from platformio import util
|
||||
|
||||
Import("env")
|
||||
|
||||
# get platformio environment variables
|
||||
project_config = util.load_project_config()
|
||||
|
||||
# check if file loraconf.h is present in source directory
|
||||
keyfile = str(env.get("PROJECTSRC_DIR")) + "/loraconf.h"
|
||||
if os.path.isfile(keyfile) and os.access(keyfile, os.R_OK):
|
||||
print "Parsing LORAWAN keys from " + keyfile
|
||||
else:
|
||||
sys.exit("Missing file loraconf.h, please create it using template loraconf.sample.h! Aborting.")
|
||||
|
||||
# check if file ota.conf is present in source directory
|
||||
keyfile = str(env.get("PROJECTSRC_DIR")) + "/" + project_config.get("common", "keyfile")
|
||||
if os.path.isfile(keyfile) and os.access(keyfile, os.R_OK):
|
||||
print "Parsing OTA keys from " + keyfile
|
||||
else:
|
||||
sys.exit("Missing file ota.conf, please create it using template ota.sample.conf! Aborting.")
|
||||
|
||||
# parse file ota.conf
|
||||
mykeys = {}
|
||||
with open(keyfile) as myfile:
|
||||
for line in myfile:
|
||||
key, value = line.partition("=")[::2]
|
||||
mykeys[key.strip()] = str(value).strip()
|
||||
|
||||
# get bintray user credentials
|
||||
user = mykeys["BINTRAY_USER"]
|
||||
repository = mykeys["BINTRAY_REPO"]
|
||||
apitoken = mykeys["BINTRAY_API_TOKEN"]
|
||||
|
||||
# get bintray upload parameters
|
||||
version = project_config.get("common", "release_version")
|
||||
package = str(env.get("PIOENV"))
|
||||
|
||||
# put bintray user credentials to platformio environment
|
||||
env.Replace(BINTRAY_USER=user)
|
||||
env.Replace(BINTRAY_REPO=repository)
|
||||
env.Replace(BINTRAY_API_TOKEN=apitoken)
|
||||
|
||||
# get runtime credentials and put them to compiler directive
|
||||
env.Replace(CPPDEFINES=[
|
||||
('WIFI_SSID', '\\"' + mykeys["OTA_WIFI_SSID"] + '\\"'),
|
||||
('WIFI_PASS', '\\"' + mykeys["OTA_WIFI_PASS"] + '\\"'),
|
||||
('BINTRAY_USER', '\\"' + mykeys["BINTRAY_USER"] + '\\"'),
|
||||
('BINTRAY_REPO', '\\"' + mykeys["BINTRAY_REPO"] + '\\"'),
|
||||
])
|
||||
|
||||
# function for pushing new firmware to bintray storage using API
|
||||
def publish_bintray(source, target, env):
|
||||
firmware_path = str(source[0])
|
||||
firmware_name = basename(firmware_path)
|
||||
url = "/".join([
|
||||
"https://api.bintray.com", "content",
|
||||
user, repository, package, version, firmware_name
|
||||
])
|
||||
|
||||
print("Uploading {0} to Bintray. Version: {1}".format(
|
||||
firmware_name, version))
|
||||
print(url)
|
||||
|
||||
headers = {
|
||||
"Content-type": "application/octet-stream",
|
||||
"X-Bintray-Publish": "1",
|
||||
"X-Bintray-Override": "1"
|
||||
}
|
||||
|
||||
r = requests.put(
|
||||
url,
|
||||
data=open(firmware_path, "rb"),
|
||||
headers=headers,
|
||||
auth=(user, apitoken))
|
||||
|
||||
if r.status_code != 201:
|
||||
print("Failed to submit package: {0}\n{1}".format(
|
||||
r.status_code, r.text))
|
||||
else:
|
||||
print("The firmware has been successfuly published at Bintray.com!")
|
||||
|
||||
# put build file name and upload command to platformio environment
|
||||
env.Replace(
|
||||
PROGNAME="firmware_" + package + "_v%s" % version,
|
||||
UPLOADCMD=publish_bintray)
|
24
lib/BintrayClient/library.json
Normal file
24
lib/BintrayClient/library.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "BintrayClient",
|
||||
"keywords": "bintray, ota, cdn, storage",
|
||||
"description": "A BintrayClient to connect to a JFrog Bintray.",
|
||||
"authors": [
|
||||
{
|
||||
"name": "PlatformIO",
|
||||
"url": "https://platformio.org/"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/platformio/platformio-examples"
|
||||
},
|
||||
"export": {
|
||||
"include": "bintray-secure-ota/lib/BintrayClient"
|
||||
},
|
||||
"dependencies": {
|
||||
"ArduinoJson": "^5.13.1"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "espressif32"
|
||||
}
|
105
lib/BintrayClient/src/BintrayCertificates.h
Normal file
105
lib/BintrayClient/src/BintrayCertificates.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Parts of this file
|
||||
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||
|
||||
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.
|
||||
**/
|
||||
|
||||
#ifndef BINTRAY_CERTIFICATES_H
|
||||
#define BINTRAY_CERTIFICATES_H
|
||||
|
||||
const char* BINTRAY_API_ROOT_CA = \
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n"
|
||||
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
|
||||
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"
|
||||
"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"
|
||||
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
|
||||
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"
|
||||
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"
|
||||
"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"
|
||||
"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"
|
||||
"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"
|
||||
"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"
|
||||
"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"
|
||||
"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"
|
||||
"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"
|
||||
"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"
|
||||
"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"
|
||||
"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"
|
||||
"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"
|
||||
"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"
|
||||
"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
const char* BINTRAY_AKAMAI_ROOT_CA = \
|
||||
"-----BEGIN CERTIFICATE-----\n"\
|
||||
"MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh\n"\
|
||||
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"\
|
||||
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"\
|
||||
"QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT\n"\
|
||||
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg\n"\
|
||||
"U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n"\
|
||||
"ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83\n"\
|
||||
"nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd\n"\
|
||||
"KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f\n"\
|
||||
"/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX\n"\
|
||||
"kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0\n"\
|
||||
"/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C\n"\
|
||||
"AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY\n"\
|
||||
"aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6\n"\
|
||||
"Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1\n"\
|
||||
"oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD\n"\
|
||||
"QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v\n"\
|
||||
"d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh\n"\
|
||||
"xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB\n"\
|
||||
"CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl\n"\
|
||||
"5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA\n"\
|
||||
"8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC\n"\
|
||||
"2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit\n"\
|
||||
"c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0\n"\
|
||||
"j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz\n"\
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
const char* CLOUDFRONT_API_ROOT_CA = \
|
||||
"-----BEGIN CERTIFICATE-----\n"\
|
||||
"MIIE3zCCA8egAwIBAgIQYxgNOPuAl3ip0DWjFhj4QDANBgkqhkiG9w0BAQsFADCB\n"\
|
||||
"yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n"\
|
||||
"ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\n"\
|
||||
"U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\n"\
|
||||
"ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\n"\
|
||||
"aG9yaXR5IC0gRzUwHhcNMTcxMTA2MDAwMDAwWhcNMjIxMTA1MjM1OTU5WjBhMQsw\n"\
|
||||
"CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\n"\
|
||||
"ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjCC\n"\
|
||||
"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALs3zTTce2vJsmiQrUp1/0a6\n"\
|
||||
"IQoIjfUZVMn7iNvzrvI6iZE8euarBhprz6wt6F4JJES6Ypp+1qOofuBUdSAFrFC3\n"\
|
||||
"nGMabDDc2h8Zsdce3v3X4MuUgzeu7B9DTt17LNK9LqUv5Km4rTrUmaS2JembawBg\n"\
|
||||
"kmD/TyFJGPdnkKthBpyP8rrptOmSMmu181foXRvNjB2rlQSVSfM1LZbjSW3dd+P7\n"\
|
||||
"SUu0rFUHqY+Vs7Qju0xtRfD2qbKVMLT9TFWMJ0pXFHyCnc1zktMWSgYMjFDRjx4J\n"\
|
||||
"vheh5iHK/YPlELyDpQrEZyj2cxQUPUZ2w4cUiSE0Ta8PRQymSaG6u5zFsTODKYUC\n"\
|
||||
"AwEAAaOCAScwggEjMB0GA1UdDgQWBBROIlQgGJXm427mD/r6uRLtBhePOTAPBgNV\n"\
|
||||
"HRMBAf8EBTADAQH/MF8GA1UdIARYMFYwVAYEVR0gADBMMCMGCCsGAQUFBwIBFhdo\n"\
|
||||
"dHRwczovL2Quc3ltY2IuY29tL2NwczAlBggrBgEFBQcCAjAZDBdodHRwczovL2Qu\n"\
|
||||
"c3ltY2IuY29tL3JwYTAvBgNVHR8EKDAmMCSgIqAghh5odHRwOi8vcy5zeW1jYi5j\n"\
|
||||
"b20vcGNhMy1nNS5jcmwwDgYDVR0PAQH/BAQDAgGGMC4GCCsGAQUFBwEBBCIwIDAe\n"\
|
||||
"BggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMB8GA1UdIwQYMBaAFH/TZafC\n"\
|
||||
"3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEBCwUAA4IBAQBQ3dNWKSUBip6n5X1N\n"\
|
||||
"ua8bjKLSJzXlnescavPECMpFBlIIKH2mc6mL2Xr/wkSIBDrsqAO3sBcmoJN+n8V3\n"\
|
||||
"0O5JelrtEAFYSyRDXfu78ZlHn6kvV5/jPUFECEM/hdN0x8WdLpGjJMqfs0EG5qHj\n"\
|
||||
"+UaxpucWD445wea4zlK7hUR+MA8fq0Yd1HEKj4c8TcgaQIHMa4KHr448cQ69e3CP\n"\
|
||||
"ECRhRNg+RAKT2I7SlaVzLvaB/8yym2oMCEsoqiRT8dbXg35aKEYmmzn3O/mnB7bG\n"\
|
||||
"Ud/EUrkIf7FVamgYZd1fSzQeg1cHqf0ja6eHpvq2bTl+cWFHaq/84KlHe5Rh0Csm\n"\
|
||||
"pZzn\n"\
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
#endif // BINTRAY_CERTIFICATES_H
|
150
lib/BintrayClient/src/BintrayClient.cpp
Normal file
150
lib/BintrayClient/src/BintrayClient.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
Parts of this file
|
||||
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||
|
||||
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.
|
||||
**/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include "BintrayClient.h"
|
||||
#include "BintrayCertificates.h"
|
||||
|
||||
BintrayClient::BintrayClient(const String &user, const String &repository, const String &package)
|
||||
: m_user(user), m_repo(repository), m_package(package),
|
||||
m_storage_host("dl.bintray.com"),
|
||||
m_api_host("api.bintray.com")
|
||||
{
|
||||
m_certificates.emplace_back("cloudfront.net", CLOUDFRONT_API_ROOT_CA);
|
||||
m_certificates.emplace_back("akamai.bintray.com", BINTRAY_AKAMAI_ROOT_CA);
|
||||
m_certificates.emplace_back("bintray.com", BINTRAY_API_ROOT_CA);
|
||||
}
|
||||
|
||||
String BintrayClient::getUser() const
|
||||
{
|
||||
return m_user;
|
||||
}
|
||||
|
||||
String BintrayClient::getRepository() const
|
||||
{
|
||||
return m_repo;
|
||||
}
|
||||
|
||||
String BintrayClient::getPackage() const
|
||||
{
|
||||
return m_package;
|
||||
}
|
||||
|
||||
String BintrayClient::getStorageHost() const
|
||||
{
|
||||
return m_storage_host;
|
||||
}
|
||||
|
||||
String BintrayClient::getApiHost() const
|
||||
{
|
||||
return m_api_host;
|
||||
}
|
||||
|
||||
String BintrayClient::getLatestVersionRequestUrl() const
|
||||
{
|
||||
return String("https://") + getApiHost() + "/packages/" + getUser() + "/" + getRepository() + "/" + getPackage() + "/versions/_latest";
|
||||
}
|
||||
|
||||
String BintrayClient::getBinaryRequestUrl(const String &version) const
|
||||
{
|
||||
return String("https://") + getApiHost() + "/packages/" + getUser() + "/" + getRepository() + "/" + getPackage() + "/versions/" + version + "/files";
|
||||
}
|
||||
|
||||
const char *BintrayClient::getCertificate(const String &url) const
|
||||
{
|
||||
for(auto& cert: m_certificates) {
|
||||
if(url.indexOf(cert.first) >= 0) {
|
||||
return cert.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the certificate for *.bintray.com by default
|
||||
return m_certificates.rbegin()->second;
|
||||
}
|
||||
|
||||
String BintrayClient::requestHTTPContent(const String &url) const
|
||||
{
|
||||
String payload;
|
||||
HTTPClient http;
|
||||
http.begin(url, getCertificate(url));
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode > 0)
|
||||
{
|
||||
if (httpCode == HTTP_CODE_OK)
|
||||
{
|
||||
payload = http.getString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "GET request failed, error: %s", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
return payload;
|
||||
}
|
||||
|
||||
String BintrayClient::getLatestVersion() const
|
||||
{
|
||||
String version;
|
||||
const String url = getLatestVersionRequestUrl();
|
||||
String jsonResult = requestHTTPContent(url);
|
||||
const size_t bufferSize = 1024;
|
||||
if (jsonResult.length() > bufferSize)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error: Firmware version data invalid.");
|
||||
return version;
|
||||
}
|
||||
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||
|
||||
JsonObject &root = jsonBuffer.parseObject(jsonResult.c_str());
|
||||
// Check for errors in parsing
|
||||
if (!root.success())
|
||||
{
|
||||
ESP_LOGE(TAG, "Error: Firmware version data not found.");
|
||||
return version;
|
||||
}
|
||||
return root.get<String>("name");
|
||||
}
|
||||
|
||||
String BintrayClient::getBinaryPath(const String &version) const
|
||||
{
|
||||
String path;
|
||||
const String url = getBinaryRequestUrl(version);
|
||||
String jsonResult = requestHTTPContent(url);
|
||||
|
||||
const size_t bufferSize = 1024;
|
||||
if (jsonResult.length() > bufferSize)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error: Firmware download path data invalid.");
|
||||
return path;
|
||||
}
|
||||
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||
|
||||
JsonArray &root = jsonBuffer.parseArray(jsonResult.c_str());
|
||||
JsonObject &firstItem = root[0];
|
||||
if (!root.success())
|
||||
{ //Check for errors in parsing
|
||||
ESP_LOGE(TAG, "Error: Firmware download path not found.");
|
||||
return path;
|
||||
}
|
||||
return "/" + getUser() + "/" + getRepository() + "/" + firstItem.get<String>("path");
|
||||
}
|
50
lib/BintrayClient/src/BintrayClient.h
Normal file
50
lib/BintrayClient/src/BintrayClient.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
Parts of this file
|
||||
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||
|
||||
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.
|
||||
**/
|
||||
|
||||
#ifndef BINTRAY_CLIENT_H
|
||||
#define BINTRAY_CLIENT_H
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <WString.h>
|
||||
|
||||
class BintrayClient {
|
||||
|
||||
public:
|
||||
BintrayClient(const String& user, const String& repository, const String& package);
|
||||
String getUser() const;
|
||||
String getRepository() const;
|
||||
String getPackage() const;
|
||||
String getStorageHost() const;
|
||||
String getApiHost() const;
|
||||
const char* getCertificate(const String& url) const;
|
||||
String getLatestVersion() const;
|
||||
String getBinaryPath(const String& version) const;
|
||||
|
||||
private:
|
||||
String requestHTTPContent(const String& url) const;
|
||||
String getLatestVersionRequestUrl() const;
|
||||
String getBinaryRequestUrl(const String& version) const;
|
||||
String m_user;
|
||||
String m_repo;
|
||||
String m_package;
|
||||
const String m_storage_host;
|
||||
const String m_api_host;
|
||||
std::vector<std::pair<String, const char*>> m_certificates;
|
||||
};
|
||||
|
||||
#endif // BINTRAY_CLIENT_H
|
@ -907,7 +907,7 @@ static ostime_t nextJoinState (void) {
|
||||
} else {
|
||||
LMIC.txChnl = os_getRndU1() & 0x3F;
|
||||
s1_t dr = DR_SF7 - ++LMIC.txCnt;
|
||||
if( dr < DR_SF10 ) {
|
||||
if( LMIC.txCnt > DR_SF7 ) {
|
||||
dr = DR_SF10;
|
||||
failed = 1; // All DR exhausted - signal failed
|
||||
}
|
||||
|
@ -790,8 +790,12 @@ void radio_irq_handler (u1_t dio) {
|
||||
// now read the FIFO
|
||||
readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
|
||||
// read rx quality parameters
|
||||
LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
|
||||
LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63)
|
||||
//LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
|
||||
LMIC.snr = ((s1_t)readReg(LORARegPktSnrValue)) / 4;
|
||||
//LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63)
|
||||
LMIC.rssi = readReg(LORARegPktRssiValue) - 157; // RFI_HF for 868 and 915MHZ band
|
||||
if (LMIC.snr < 0)
|
||||
LMIC.rssi += LMIC.snr;
|
||||
} else if( flags & IRQ_LORA_RXTOUT_MASK ) {
|
||||
// indicate timeout
|
||||
LMIC.dataLen = 0;
|
||||
|
276
platformio.ini
276
platformio.ini
@ -1,10 +1,5 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; http://docs.platformio.org/page/projectconf.html
|
||||
|
||||
@ -16,7 +11,8 @@ env_default = generic
|
||||
;env_default = heltec
|
||||
;env_default = ttgov1
|
||||
;env_default = ttgov2
|
||||
;env_default = ttgov21
|
||||
;env_default = ttgov21old
|
||||
;env_default = ttgov21new
|
||||
;env_default = ttgobeam
|
||||
;env_default = lopy
|
||||
;env_default = lopy4
|
||||
@ -24,14 +20,27 @@ env_default = generic
|
||||
;env_default = lolin32litelora
|
||||
;env_default = lolin32lora
|
||||
;env_default = lolin32lite
|
||||
;env_default = octopus32
|
||||
;env_default = ebox, heltec, ttgobeam, lopy4, lopy, ttgov21old, ttgov21new
|
||||
;
|
||||
description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around.
|
||||
|
||||
[common_env_data]
|
||||
platform_espressif32 = espressif32@1.3.0
|
||||
;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage
|
||||
board_build.partitions = no_ota.csv
|
||||
lib_deps_all =
|
||||
[common]
|
||||
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
||||
release_version = 1.6.0
|
||||
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
||||
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||
debug_level = 0
|
||||
; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA
|
||||
upload_protocol = esptool
|
||||
;upload_protocol = custom
|
||||
extra_scripts = pre:build.py
|
||||
keyfile = ota.conf
|
||||
platform_espressif32 = espressif32@1.4.0
|
||||
board_build.partitions = min_spiffs.csv
|
||||
monitor_speed = 115200
|
||||
lib_deps_all =
|
||||
ArduinoJson@^5.13.1
|
||||
lib_deps_display =
|
||||
U8g2@>=2.23.16
|
||||
lib_deps_rgbled =
|
||||
@ -39,199 +48,242 @@ lib_deps_rgbled =
|
||||
lib_deps_gps =
|
||||
TinyGPSPlus@>=1.0.2
|
||||
Time@>=1.5
|
||||
build_flags =
|
||||
; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <---
|
||||
; otherwise device may leak RAM
|
||||
;
|
||||
; None
|
||||
-DCORE_DEBUG_LEVEL=0
|
||||
; Error
|
||||
; -DCORE_DEBUG_LEVEL=1
|
||||
; Warn
|
||||
; -DCORE_DEBUG_LEVEL=2
|
||||
; Info
|
||||
; -DCORE_DEBUG_LEVEL=3
|
||||
; Debug
|
||||
; -DCORE_DEBUG_LEVEL=4
|
||||
; Verbose
|
||||
; -DCORE_DEBUG_LEVEL=5
|
||||
;
|
||||
build_flags =
|
||||
; override lora settings from LMiC library in lmic/config.h and use main.h instead
|
||||
-D_lmic_config_h_
|
||||
-include "src/paxcounter.conf"
|
||||
-include "src/hal/${PIOENV}.h"
|
||||
-w
|
||||
|
||||
'-DCORE_DEBUG_LEVEL=${common.debug_level}'
|
||||
'-DBINTRAY_PACKAGE="${PIOENV}"'
|
||||
'-DPROGVERSION="${common.release_version}"'
|
||||
|
||||
[env:ebox]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 115200
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common.lib_deps_all}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:heltec]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = heltec_wifi_lora_32
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
upload_speed = 115200
|
||||
monitor_speed = 115200
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_display}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_display}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:ttgov1]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 115200
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_display}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_display}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:ttgov2]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_display}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_display}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:ttgov21]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
[env:ttgov21old]
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_display}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_display}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:ttgov21new]
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
lib_deps =
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_display}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:ttgobeam]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_gps}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_gps}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
-mfix-esp32-psram-cache-issue
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:fipy]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_rgbled}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_rgbled}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:lopy]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_rgbled}
|
||||
${common_env_data.lib_deps_gps}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_rgbled}
|
||||
${common.lib_deps_gps}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:lopy4]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_rgbled}
|
||||
${common_env_data.lib_deps_gps}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_rgbled}
|
||||
${common.lib_deps_gps}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
-mfix-esp32-psram-cache-issue
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:lolin32litelora]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = lolin32
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_rgbled}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_rgbled}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:lolin32lora]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = lolin32
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_rgbled}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_rgbled}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:lolin32lite]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = lolin32
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_rgbled}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_rgbled}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:octopus32]
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
lib_deps =
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_rgbled}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
||||
[env:generic]
|
||||
platform = ${common_env_data.platform_espressif32}
|
||||
platform = ${common.platform_espressif32}
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||
board_build.partitions = ${common.board_build.partitions}
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_all}
|
||||
${common_env_data.lib_deps_rgbled}
|
||||
${common_env_data.lib_deps_gps}
|
||||
${common_env_data.lib_deps_display}
|
||||
${common.lib_deps_all}
|
||||
${common.lib_deps_rgbled}
|
||||
${common.lib_deps_gps}
|
||||
${common.lib_deps_display}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common.build_flags}
|
||||
upload_protocol = ${common.upload_protocol}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
|
@ -18,13 +18,12 @@ function Decoder(bytes, port) {
|
||||
|
||||
if (port === 2) {
|
||||
// device status data
|
||||
return decode(bytes, [uint16, uptime, uint8, uint32], ['voltage', 'uptime', 'cputemp', 'memory']);
|
||||
return decode(bytes, [uint16, uptime, uint8, uint32, uint8, uint8], ['voltage', 'uptime', 'cputemp', 'memory', 'reset0', 'reset1']);
|
||||
}
|
||||
|
||||
|
||||
if (port === 3) {
|
||||
// device config data
|
||||
return decode(bytes, [uint8, uint8, uint16, uint8, uint8, uint8, uint8, bitmap], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']);
|
||||
return decode(bytes, [uint8, uint8, uint16, uint8, uint8, uint8, uint8, bitmap, version], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags', 'version']);
|
||||
}
|
||||
|
||||
if (port === 4) {
|
||||
@ -56,6 +55,14 @@ var bytesToInt = function (bytes) {
|
||||
return i;
|
||||
};
|
||||
|
||||
var version = function (bytes) {
|
||||
if (bytes.length !== version.BYTES) {
|
||||
throw new Error('version must have exactly 10 bytes');
|
||||
}
|
||||
return String.fromCharCode.apply(null, bytes).split('\u0000')[0];
|
||||
};
|
||||
version.BYTES = 10;
|
||||
|
||||
var uint8 = function (bytes) {
|
||||
if (bytes.length !== uint8.BYTES) {
|
||||
throw new Error('uint8 must have exactly 1 byte');
|
||||
@ -186,6 +193,7 @@ if (typeof module === 'object' && typeof module.exports !== 'undefined') {
|
||||
latLng: latLng,
|
||||
hdop: hdop,
|
||||
bitmap: bitmap,
|
||||
version: version,
|
||||
decode: decode
|
||||
};
|
||||
}
|
@ -25,6 +25,9 @@ function Decoder(bytes, port) {
|
||||
decoded.uptime = ((bytes[i++] << 56) | (bytes[i++] << 48) | (bytes[i++] << 40) | (bytes[i++] << 32) |
|
||||
(bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]);
|
||||
decoded.temp = bytes[i++];
|
||||
decoded.memory = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]);
|
||||
decoded.reset0 = bytes[i++];
|
||||
decoded.reset1 = bytes[i++];
|
||||
}
|
||||
|
||||
if (port === 5) {
|
||||
|
@ -49,4 +49,9 @@ uint16_t read_voltage() {
|
||||
return voltage;
|
||||
}
|
||||
|
||||
bool batt_sufficient() {
|
||||
uint16_t volts = read_voltage();
|
||||
return (( volts < 1000 ) || (volts > OTA_MIN_BATT)); // no battery or battery sufficient
|
||||
}
|
||||
|
||||
#endif // HAS_BATTERY_PROBE
|
@ -9,5 +9,6 @@
|
||||
|
||||
uint16_t read_voltage(void);
|
||||
void calibrate_voltage(void);
|
||||
bool batt_sufficient(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,22 +1,15 @@
|
||||
#ifdef HAS_BUTTON
|
||||
|
||||
#include "globals.h"
|
||||
#include "senddata.h"
|
||||
#include "button.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
void IRAM_ATTR ButtonIRQ() { ButtonPressedIRQ++; }
|
||||
|
||||
void readButton() {
|
||||
if (ButtonPressedIRQ) {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
ButtonPressedIRQ = 0;
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
ESP_LOGI(TAG, "Button pressed");
|
||||
payload.reset();
|
||||
payload.addButton(0x01);
|
||||
SendData(BUTTONPORT);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,7 +1,8 @@
|
||||
#ifndef _BUTTON_H
|
||||
#define _BUTTON_H
|
||||
|
||||
void IRAM_ATTR ButtonIRQ(void);
|
||||
void readButton(void);
|
||||
#include "senddata.h"
|
||||
|
||||
void readButton();
|
||||
|
||||
#endif
|
@ -31,6 +31,7 @@ void defaultConfig() {
|
||||
cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
|
||||
cfg.gpsmode = 1; // 0=disabled, 1=enabled
|
||||
cfg.monitormode = 0; // 0=disabled, 1=enabled
|
||||
cfg.runmode = 0; // 0=normal, 1=update
|
||||
|
||||
strncpy(cfg.version, PROGVERSION, sizeof(cfg.version) - 1);
|
||||
}
|
||||
@ -143,6 +144,10 @@ void saveConfig() {
|
||||
flash8 != cfg.monitormode)
|
||||
nvs_set_i8(my_handle, "monitormode", cfg.monitormode);
|
||||
|
||||
if (nvs_get_i8(my_handle, "runmode", &flash8) != ESP_OK ||
|
||||
flash8 != cfg.runmode)
|
||||
nvs_set_i8(my_handle, "runmode", cfg.runmode);
|
||||
|
||||
if (nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK ||
|
||||
flash16 != cfg.rssilimit)
|
||||
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
|
||||
@ -326,6 +331,14 @@ void loadConfig() {
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if (nvs_get_i8(my_handle, "runmode", &flash8) == ESP_OK) {
|
||||
cfg.runmode = flash8;
|
||||
ESP_LOGI(TAG, "Run mode = %d", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Run mode set to default %d", cfg.runmode);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
nvs_close(my_handle);
|
||||
ESP_LOGI(TAG, "Done");
|
||||
}
|
||||
|
@ -2,18 +2,36 @@
|
||||
/* Interval can be set in paxcounter.conf (HOMECYCLE) */
|
||||
|
||||
// Basic config
|
||||
#include "globals.h"
|
||||
#include "senddata.h"
|
||||
#include "cyclic.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
// do all housekeeping
|
||||
void doHomework() {
|
||||
void doHousekeeping() {
|
||||
|
||||
// update uptime counter
|
||||
uptime();
|
||||
|
||||
// check if update mode trigger switch was set
|
||||
if (cfg.runmode == 1)
|
||||
ESP.restart();
|
||||
|
||||
// task storage debugging //
|
||||
ESP_LOGD(TAG, "Wifiloop %d bytes left",
|
||||
uxTaskGetStackHighWaterMark(wifiSwitchTask));
|
||||
ESP_LOGD(TAG, "IRQhandler %d bytes left",
|
||||
uxTaskGetStackHighWaterMark(irqHandlerTask));
|
||||
#ifdef HAS_GPS
|
||||
ESP_LOGD(TAG, "Gpsloop %d bytes left", uxTaskGetStackHighWaterMark(GpsTask));
|
||||
#endif
|
||||
#ifdef HAS_SPI
|
||||
ESP_LOGD(TAG, "Spiloop %d bytes left", uxTaskGetStackHighWaterMark(SpiTask));
|
||||
#endif
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
ESP_LOGD(TAG, "LEDloop %d bytes left", uxTaskGetStackHighWaterMark(ledLoopTask));
|
||||
#endif
|
||||
|
||||
// read battery voltage into global variable
|
||||
#ifdef HAS_BATTERY_PROBE
|
||||
batt_voltage = read_voltage();
|
||||
@ -39,27 +57,12 @@ void doHomework() {
|
||||
esp_get_minimum_free_heap_size(), ESP.getFreeHeap());
|
||||
SendData(COUNTERPORT); // send data before clearing counters
|
||||
reset_counters(); // clear macs container and reset all counters
|
||||
reset_salt(); // get new salt for salting hashes
|
||||
get_salt(); // get new salt for salting hashes
|
||||
|
||||
if (esp_get_minimum_free_heap_size() <= MEM_LOW) // check again
|
||||
esp_restart(); // memory leak, reset device
|
||||
}
|
||||
} // doHomework()
|
||||
|
||||
void checkHousekeeping() {
|
||||
if (HomeCycleIRQ) {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
HomeCycleIRQ = 0;
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
doHomework();
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR homeCycleIRQ() {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
HomeCycleIRQ++;
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
}
|
||||
} // doHousekeeping()
|
||||
|
||||
// uptime counter 64bit to prevent millis() rollover after 49 days
|
||||
uint64_t uptime() {
|
||||
|
@ -1,9 +1,10 @@
|
||||
#ifndef _CYCLIC_H
|
||||
#define _CYCLIC_H
|
||||
|
||||
void doHomework(void);
|
||||
void checkHousekeeping(void);
|
||||
void homeCycleIRQ(void);
|
||||
#include "globals.h"
|
||||
#include "senddata.h"
|
||||
|
||||
void doHousekeeping(void);
|
||||
uint64_t uptime(void);
|
||||
void reset_counters(void);
|
||||
int redirect_log(const char *fmt, va_list args);
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "globals.h"
|
||||
#include <esp_spi_flash.h> // needed for reading ESP32 chip attributes
|
||||
|
||||
HAS_DISPLAY u8x8(OLED_RST, OLED_SCL, OLED_SDA);
|
||||
HAS_DISPLAY u8x8(OLED_RST, I2C_SCL, I2C_SDA);
|
||||
|
||||
// helper string for converting LoRa spread factor values
|
||||
#if defined(CFG_eu868)
|
||||
@ -13,7 +13,7 @@ const char lora_datarate[] = {"1211100908077BFSNA"};
|
||||
const char lora_datarate[] = {"100908078CNA121110090807"};
|
||||
#endif
|
||||
|
||||
uint8_t DisplayState = 0;
|
||||
uint8_t volatile DisplayState = 0;
|
||||
|
||||
// helper function, prints a hex key on display
|
||||
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) {
|
||||
@ -25,8 +25,9 @@ void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) {
|
||||
u8x8.printf("\n");
|
||||
}
|
||||
|
||||
// show startup screen
|
||||
void init_display(const char *Productname, const char *Version) {
|
||||
|
||||
// show startup screen
|
||||
uint8_t buf[32];
|
||||
u8x8.begin();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
@ -36,14 +37,14 @@ void init_display(const char *Productname, const char *Version) {
|
||||
u8x8.draw2x2String(0, 0, Productname);
|
||||
u8x8.setInverseFont(0);
|
||||
u8x8.draw2x2String(2, 2, Productname);
|
||||
delay(1500);
|
||||
vTaskDelay(1500 / portTICK_PERIOD_MS);
|
||||
u8x8.clear();
|
||||
u8x8.setFlipMode(1);
|
||||
u8x8.setInverseFont(1);
|
||||
u8x8.draw2x2String(0, 0, Productname);
|
||||
u8x8.setInverseFont(0);
|
||||
u8x8.draw2x2String(2, 2, Productname);
|
||||
delay(1500);
|
||||
vTaskDelay(1500 / portTICK_PERIOD_MS);
|
||||
|
||||
u8x8.setFlipMode(0);
|
||||
u8x8.clear();
|
||||
@ -74,7 +75,7 @@ void init_display(const char *Productname, const char *Version) {
|
||||
DisplayKey(buf, 8, true);
|
||||
#endif // HAS_LORA
|
||||
|
||||
delay(5000);
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
u8x8.clear();
|
||||
u8x8.setPowerSave(!cfg.screenon); // set display off if disabled
|
||||
u8x8.draw2x2String(0, 0, "PAX:0");
|
||||
@ -101,7 +102,7 @@ void refreshtheDisplay() {
|
||||
if (!DisplayState)
|
||||
return;
|
||||
|
||||
uint8_t msgWaiting = 0;
|
||||
uint8_t msgWaiting;
|
||||
char buff[16]; // 16 chars line buffer
|
||||
|
||||
// update counter (lines 0-1)
|
||||
@ -114,7 +115,8 @@ void refreshtheDisplay() {
|
||||
// update Battery status (line 2)
|
||||
#ifdef HAS_BATTERY_PROBE
|
||||
u8x8.setCursor(0, 2);
|
||||
u8x8.printf(batt_voltage > 4000 ? "B:USB " : "B:%.1fV", batt_voltage / 1000.0);
|
||||
u8x8.printf(batt_voltage > 4000 ? "B:USB " : "B:%.1fV",
|
||||
batt_voltage / 1000.0);
|
||||
#endif
|
||||
|
||||
// update GPS status (line 2)
|
||||
@ -126,7 +128,7 @@ void refreshtheDisplay() {
|
||||
u8x8.printf("Sats:%.2d", gps.satellites.value());
|
||||
u8x8.setInverseFont(0);
|
||||
} else
|
||||
u8x8.printf("Sats:%.d", gps.satellites.value());
|
||||
u8x8.printf("Sats:%.2d", gps.satellites.value());
|
||||
#endif
|
||||
|
||||
// update bluetooth counter + LoRa SF (line 3)
|
||||
@ -185,19 +187,4 @@ void refreshtheDisplay() {
|
||||
|
||||
} // refreshDisplay()
|
||||
|
||||
void IRAM_ATTR DisplayIRQ() {
|
||||
portENTER_CRITICAL_ISR(&timerMux);
|
||||
DisplayTimerIRQ++;
|
||||
portEXIT_CRITICAL_ISR(&timerMux);
|
||||
}
|
||||
|
||||
void updateDisplay() {
|
||||
if (DisplayTimerIRQ) {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
DisplayTimerIRQ = 0;
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
refreshtheDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAS_DISPLAY
|
@ -3,12 +3,11 @@
|
||||
|
||||
#include <U8x8lib.h>
|
||||
|
||||
extern uint8_t DisplayState;
|
||||
extern uint8_t volatile DisplayState;
|
||||
extern HAS_DISPLAY u8x8;
|
||||
|
||||
void init_display(const char *Productname, const char *Version);
|
||||
void refreshtheDisplay(void);
|
||||
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb);
|
||||
void updateDisplay(void);
|
||||
void DisplayIRQ(void);
|
||||
|
||||
#endif
|
@ -4,10 +4,6 @@
|
||||
// The mother of all embedded development...
|
||||
#include <Arduino.h>
|
||||
|
||||
// attn: increment version after modifications to configData_t truct!
|
||||
#define PROGVERSION "1.4.23" // use max 10 chars here!
|
||||
#define PROGNAME "PAXCNT"
|
||||
|
||||
// std::set for unified array functions
|
||||
#include <set>
|
||||
#include <array>
|
||||
@ -31,6 +27,7 @@ typedef struct {
|
||||
uint8_t rgblum; // RGB Led luminosity (0..100%)
|
||||
uint8_t gpsmode; // 0=disabled, 1=enabled
|
||||
uint8_t monitormode; // 0=disabled, 1=enabled
|
||||
uint8_t runmode; // 0=normal, 1=update
|
||||
char version[10]; // Firmware version
|
||||
} configData_t;
|
||||
|
||||
@ -44,23 +41,22 @@ typedef struct {
|
||||
// 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, batt_voltage; // display values
|
||||
extern uint8_t volatile channel; // wifi channel rotation counter
|
||||
extern uint16_t volatile macs_total, macs_wifi, macs_ble,
|
||||
batt_voltage; // display values
|
||||
extern std::set<uint16_t> macs; // temp storage for MACs
|
||||
extern hw_timer_t *channelSwitch, *sendCycle;
|
||||
extern portMUX_TYPE timerMux;
|
||||
extern volatile int SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ,
|
||||
ChannelTimerIRQ, ButtonPressedIRQ;
|
||||
extern QueueHandle_t LoraSendQueue, SPISendQueue;
|
||||
|
||||
extern std::array<uint64_t, 0xff>::iterator it;
|
||||
extern std::array<uint64_t, 0xff> beacons;
|
||||
|
||||
extern TaskHandle_t irqHandlerTask, wifiSwitchTask;
|
||||
|
||||
#ifdef HAS_GPS
|
||||
#include "gps.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_LED
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
#include "led.h"
|
||||
#endif
|
||||
|
||||
@ -70,6 +66,10 @@ extern std::array<uint64_t, 0xff> beacons;
|
||||
#include "lorawan.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPI
|
||||
#include "spi.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
#include "display.h"
|
||||
#endif
|
||||
|
63
src/gps.cpp
63
src/gps.cpp
@ -5,8 +5,9 @@
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
TinyGPSPlus gps;
|
||||
TinyGPSPlus gps;
|
||||
gpsStatus_t gps_status;
|
||||
TaskHandle_t GpsTask;
|
||||
|
||||
// read GPS data and cast to global struct
|
||||
void gps_read() {
|
||||
@ -25,52 +26,50 @@ void gps_loop(void *pvParameters) {
|
||||
// initialize and, if needed, configure, GPS
|
||||
#if defined GPS_SERIAL
|
||||
HardwareSerial GPS_Serial(1);
|
||||
GPS_Serial.begin(GPS_SERIAL);
|
||||
|
||||
#elif defined GPS_QUECTEL_L76
|
||||
uint8_t ret;
|
||||
Wire.begin(GPS_QUECTEL_L76, 400000); // I2C connect to GPS device with 400 KHz
|
||||
Wire.beginTransmission(GPS_ADDR);
|
||||
Wire.write(0x00); // dummy write
|
||||
ret = Wire.endTransmission(); // check if chip is seen on i2c bus
|
||||
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG,
|
||||
"Quectel L76 GPS chip not found on i2c bus, bus error %d. "
|
||||
"Stopping GPS-Task.",
|
||||
ret);
|
||||
vTaskDelete(GpsTask);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Quectel L76 GPS chip found.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
|
||||
if (cfg.gpsmode) {
|
||||
#if defined GPS_SERIAL
|
||||
|
||||
// serial connect to GPS device
|
||||
GPS_Serial.begin(GPS_SERIAL);
|
||||
|
||||
while (cfg.gpsmode) {
|
||||
// feed GPS decoder with serial NMEA data from GPS device
|
||||
while (GPS_Serial.available()) {
|
||||
gps.encode(GPS_Serial.read());
|
||||
}
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||
// feed GPS decoder with serial NMEA data from GPS device
|
||||
while (GPS_Serial.available()) {
|
||||
gps.encode(GPS_Serial.read());
|
||||
}
|
||||
// after GPS function was disabled, close connect to GPS device
|
||||
GPS_Serial.end();
|
||||
|
||||
#elif defined GPS_QUECTEL_L76
|
||||
|
||||
Wire.beginTransmission(GPS_ADDR);
|
||||
Wire.write(0x00); // dummy write to start read
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.beginTransmission(GPS_ADDR);
|
||||
while (cfg.gpsmode) {
|
||||
Wire.requestFrom(GPS_ADDR | 0x01, 32);
|
||||
while (Wire.available()) {
|
||||
gps.encode(Wire.read());
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS); // polling mode: 500ms sleep
|
||||
}
|
||||
Wire.requestFrom(GPS_ADDR, 32); // caution: this is a blocking call
|
||||
while (Wire.available()) {
|
||||
gps.encode(Wire.read());
|
||||
vTaskDelay(2 / portTICK_PERIOD_MS); // 2ms delay according L76 datasheet
|
||||
}
|
||||
// after GPS function was disabled, close connect to GPS device
|
||||
Wire.endTransmission();
|
||||
#endif
|
||||
} // if (cfg.gpsmode)
|
||||
|
||||
#endif // GPS Type
|
||||
}
|
||||
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||
vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU
|
||||
|
||||
} // end of infinite loop
|
||||
|
||||
vTaskDelete(NULL); // shoud never be reached
|
||||
|
||||
} // gps_loop()
|
||||
|
||||
#endif // HAS_GPS
|
12
src/gps.h
12
src/gps.h
@ -1,9 +1,13 @@
|
||||
#ifndef _GPS_H
|
||||
#define _GPS_H
|
||||
|
||||
#include <TinyGPS++.h> // library for parsing NMEA data
|
||||
#include <TinyGPS++.h> // library for parsing NMEA data
|
||||
#include <TimeLib.h>
|
||||
|
||||
#ifdef GPS_QUECTEL_L76 // Needed for reading from I2C Bus
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t latitude;
|
||||
uint32_t longitude;
|
||||
@ -12,8 +16,10 @@ typedef struct {
|
||||
uint16_t altitude;
|
||||
} gpsStatus_t;
|
||||
|
||||
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
||||
extern gpsStatus_t gps_status; // Make struct for storing gps data globally available
|
||||
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
||||
extern gpsStatus_t
|
||||
gps_status; // Make struct for storing gps data globally available
|
||||
extern TaskHandle_t GpsTask;
|
||||
|
||||
void gps_read(void);
|
||||
void gps_loop(void *pvParameters);
|
||||
|
@ -34,5 +34,9 @@
|
||||
|
||||
// pin definitions for I2C interface of OLED Display
|
||||
#define OLED_RST GPIO_NUM_16 // SSD1306 RST
|
||||
#define OLED_SDA GPIO_NUM_4 // SD1306 D1+D2
|
||||
#define OLED_SCL GPIO_NUM_15 // SD1306 D0
|
||||
#define I2C_SDA GPIO_NUM_4 // SD1306 D1+D2
|
||||
#define I2C_SCL GPIO_NUM_15 // SD1306 D0
|
||||
|
||||
// I2C config for Microchip 24AA02E64 DEVEUI unique address
|
||||
#define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64
|
||||
#define MCP_24AA02E64_MAC_ADDRESS 0xF8 // Memory adress of unique deveui 64 bits
|
@ -22,5 +22,5 @@
|
||||
|
||||
// Hardware pin definitions for Heltec LoRa-32 Board with OLED SSD1306 I2C Display
|
||||
#define OLED_RST GPIO_NUM_16 // ESP32 GPIO16 (Pin16) -- SD1306 RST
|
||||
#define OLED_SDA GPIO_NUM_4 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2
|
||||
#define OLED_SCL GPIO_NUM_15 // ESP32 GPIO15 (Pin15) -- SD1306 D0
|
||||
#define I2C_SDA GPIO_NUM_4 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2
|
||||
#define I2C_SCL GPIO_NUM_15 // ESP32 GPIO15 (Pin15) -- SD1306 D0
|
||||
|
26
src/hal/heltecv2.h
Normal file
26
src/hal/heltecv2.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Hardware related definitions for Heltec V2 LoRa-32 Board
|
||||
|
||||
#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
|
||||
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
||||
#define HAS_LED GPIO_NUM_25 // white LED on board
|
||||
#define HAS_BUTTON GPIO_NUM_0 // button "PROG" on board
|
||||
|
||||
// re-define pin definitions of pins_arduino.h
|
||||
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 -- SX1276 NSS (Pin19) SPI Chip Select Input
|
||||
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 -- SX1276 MOSI (Pin18) SPI Data Input
|
||||
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 -- SX1276 MISO (Pin17) SPI Data Output
|
||||
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 -- SX1276 SCK (Pin16) SPI Clock Input
|
||||
|
||||
// non arduino pin definitions
|
||||
#define RST GPIO_NUM_14 // ESP32 GPIO18 -- SX1276 NRESET (Pin7) Reset Trigger Input
|
||||
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
|
||||
#define DIO1 GPIO_NUM_34 // ESP32 GPIO33 -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
|
||||
#define DIO2 GPIO_NUM_35 // 32 ESP32 GPIO32 -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
|
||||
|
||||
// Hardware pin definitions for Heltec LoRa-32 Board with OLED SSD1306 I2C Display
|
||||
#define OLED_RST GPIO_NUM_16 // ESP32 GPIO16 -- SD1306 RST
|
||||
#define I2C_SDA GPIO_NUM_4 // ESP32 GPIO4 -- SD1306 D1+D2
|
||||
#define I2C_SCL GPIO_NUM_15 // ESP32 GPIO15 -- SD1306 D0
|
@ -31,8 +31,8 @@
|
||||
|
||||
// Hardware pin definitions for LoRaNode32 Board with OLED I2C Display
|
||||
#define OLED_RST U8X8_PIN_NONE // Not reset pin
|
||||
#define OLED_SDA 14 // ESP32 GPIO14 (Pin14) -- OLED SDA
|
||||
#define OLED_SCL 12 // ESP32 GPIO12 (Pin12) -- OLED SCL
|
||||
#define I2C_SDA 14 // ESP32 GPIO14 (Pin14) -- OLED SDA
|
||||
#define I2C_SCL 12 // ESP32 GPIO12 (Pin12) -- OLED SCL
|
||||
|
||||
// I2C config for Microchip 24AA02E64 DEVEUI unique address
|
||||
#define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64
|
||||
|
@ -32,8 +32,8 @@
|
||||
|
||||
// Hardware pin definitions for LoRaNode32 Board with OLED I2C Display
|
||||
#define OLED_RST U8X8_PIN_NONE // Not reset pin
|
||||
#define OLED_SDA 21 // ESP32 GPIO21 (Pin21) -- OLED SDA
|
||||
#define OLED_SCL 22 // ESP32 GPIO22 (Pin22) -- OLED SCL
|
||||
#define I2C_SDA 21 // ESP32 GPIO21 (Pin21) -- OLED SDA
|
||||
#define I2C_SCL 22 // ESP32 GPIO22 (Pin22) -- OLED SCL
|
||||
|
||||
// I2C config for Microchip 24AA02E64 DEVEUI unique address
|
||||
#define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64
|
||||
|
@ -3,7 +3,7 @@
|
||||
#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_sx1272_radio 1
|
||||
#define HAS_LED NOT_A_PIN // LoPy has no on board LED, so we use RGB LED on LoPy
|
||||
#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED
|
||||
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
|
||||
|
||||
// Hardware pin definitions for Pycom LoPy board
|
||||
@ -17,26 +17,19 @@
|
||||
#define DIO2 GPIO_NUM_23 // Pin tied via diode to DIO0
|
||||
|
||||
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
||||
#define HAS_ANTENNA_SWITCH 16 // pin for switching wifi antenna
|
||||
#define HAS_ANTENNA_SWITCH GPIO_NUM_16 // pin for switching wifi antenna
|
||||
#define WIFI_ANTENNA 0 // 0 = internal, 1 = external
|
||||
|
||||
// !!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
|
||||
// uncomment this only if your LoPy runs on a PYTRACK BOARD
|
||||
//#define HAS_GPS 1
|
||||
//#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21)
|
||||
//#define GPS_ADDR 0x10
|
||||
//#define HAS_BUTTON GPIO_NUM_37 // (P14)
|
||||
//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
|
||||
// uncomment this only if your LoPy runs on a expansion board 3.0
|
||||
//#define HAS_BATTERY_PROBE ADC1_GPIO39_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
//#define BATT_FACTOR 2 // voltage divider 1MOhm/1MOhm on board
|
||||
//#define HAS_BUTTON GPIO_NUM_37 // (P14)
|
||||
// uncomment this only if your LoPy runs on a EXPANSION BOARD
|
||||
//#define HAS_LED GPIO_NUM_12 // use if LoPy is on Expansion Board, this has a user LED
|
||||
//#define LED_ACTIVE_LOW 1 // use if LoPy is on Expansion Board, this has a user LED
|
||||
//#define HAS_BUTTON GPIO_NUM_13 // user button on expansion board
|
||||
//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
|
||||
// uncomment this only if your LoPy runs on a expansion board 2.0
|
||||
//#define HAS_BATTERY_PROBE ADC1_GPIO39_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
//#define BATT_FACTOR 4 // voltage divider 115kOhm/56kOhm on board
|
||||
//#define HAS_BUTTON GPIO_NUM_13 // (P10)
|
||||
//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
//#define BATT_FACTOR 2 // voltage divider 1MOhm/1MOhm -> expansion board 3.0
|
||||
//#define BATT_FACTOR 4 // voltage divider 115kOhm/56kOhm -> expansion board 2.0
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Hardware related definitions for Pycom LoPy Board (not: LoPy4)
|
||||
// Hardware related definitions for Pycom LoPy4 Board
|
||||
|
||||
#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
|
||||
#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
|
||||
//#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED
|
||||
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0 (P2)
|
||||
#define BOARD_HAS_PSRAM // use extra 4MB extern RAM
|
||||
|
||||
// Hardware pin definitions for Pycom LoPy4 board
|
||||
@ -18,26 +18,19 @@
|
||||
#define DIO2 GPIO_NUM_23 // Pin tied via diode to DIO0
|
||||
|
||||
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
||||
#define HAS_ANTENNA_SWITCH 21 // pin for switching wifi antenna
|
||||
#define WIFI_ANTENNA 0 // 0 = internal, 1 = external
|
||||
#define HAS_ANTENNA_SWITCH GPIO_NUM_21 // pin for switching wifi antenna (P12)
|
||||
#define WIFI_ANTENNA 0 // 0 = internal, 1 = external
|
||||
|
||||
// !!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
|
||||
// uncomment this only if your LoPy runs on a PYTRACK BOARD
|
||||
//#define HAS_GPS 1
|
||||
//#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21)
|
||||
//#define GPS_ADDR 0x10
|
||||
//#define HAS_BUTTON GPIO_NUM_37 // (P14)
|
||||
//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
|
||||
// uncomment this only if your LoPy runs on a expansion board 3.0
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO39_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
#define BATT_FACTOR 2 // voltage divider 1MOhm/1MOhm on board
|
||||
#define HAS_BUTTON GPIO_NUM_37 // (P14)
|
||||
// uncomment this only if your LoPy runs on a EXPANSION BOARD
|
||||
#define HAS_LED GPIO_NUM_12 // use if LoPy is on Expansion Board, this has a user LED
|
||||
#define LED_ACTIVE_LOW 1 // use if LoPy is on Expansion Board, this has a user LED
|
||||
#define HAS_BUTTON GPIO_NUM_13 // user button on expansion board
|
||||
#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
|
||||
// uncomment this only if your LoPy runs on a expansion board 2.0
|
||||
//#define HAS_BATTERY_PROBE ADC1_GPIO39_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
//#define BATT_FACTOR 4 // voltage divider 115kOhm/56kOhm on board
|
||||
//#define HAS_BUTTON GPIO_NUM_13 // (P10)
|
||||
//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO39_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
#define BATT_FACTOR 2 // voltage divider 1MOhm/1MOhm -> expansion board 3.0
|
||||
//#define BATT_FACTOR 4 // voltage divider 115kOhm/56kOhm -> expansion board 2.0
|
41
src/hal/octopus32.h
Normal file
41
src/hal/octopus32.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Hardware related definitions for #IoT Octopus32 with the Adafruit LoRaWAN Wing
|
||||
// You can use this configuration also with the Adafruit ESP32 Feather + the LoRaWAN Wing
|
||||
// In this config we use the Adafruit OLED Wing which is only 128x32 pixel, need to find a smaller font
|
||||
|
||||
// disable brownout detection (avoid unexpected reset on some boards)
|
||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
|
||||
#define HAS_LED 13 // ESP32 GPIO12 (pin22) On Board LED
|
||||
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
||||
//#define HAS_RGB_LED 13 // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED
|
||||
//#define HAS_BUTTON 15 // ESP32 GPIO15 (pin15) Button is on the LoraNode32 shield
|
||||
//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
|
||||
|
||||
#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 // RFM95 module
|
||||
|
||||
// re-define pin definitions of pins_arduino.h
|
||||
#define PIN_SPI_SS 14 //14 // ESP32 GPIO5 (Pin5) -- SX1276 NSS (Pin19) SPI Chip Select Input
|
||||
#define PIN_SPI_MOSI 18 // ESP32 GPIO23 (Pin23) -- SX1276 MOSI (Pin18) SPI Data Input
|
||||
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
|
||||
#define PIN_SPI_SCK 5 // ESP32 GPIO18 (Pin18) -- SX1276 SCK (Pin16) SPI Clock Input
|
||||
|
||||
//GPIO_NUM_
|
||||
// non arduino pin definitions
|
||||
#define RST LMIC_UNUSED_PIN // ESP32 GPIO25 (Pin25) -- SX1276 NRESET (Pin7) Reset Trigger Input
|
||||
#define DIO0 33 // ESP32 GPIO27 (Pin27) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
|
||||
#define DIO1 33 // ESP32 GPIO26 (Pin26) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
|
||||
#define DIO2 LMIC_UNUSED_PIN // 4 ESP32 GPIO4 (Pin4) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
|
||||
#define DIO5 LMIC_UNUSED_PIN // 35 ESP32 GPIO35 (Pin35) -- SX1276 DIO5 not used by LMIC for LoRa (Timeout for FSK only)
|
||||
|
||||
// Hardware pin definitions for LoRaNode32 Board with OLED I2C Display
|
||||
#define OLED_RST U8X8_PIN_NONE // Not reset pin
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // U8X8_SSD1306_128X32_UNIVISION_SW_I2C //
|
||||
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
|
||||
#define I2C_SDA 23 //21 // ESP32 GPIO14 (Pin14) -- OLED SDA
|
||||
#define I2C_SCL 22 //22 // ESP32 GPIO12 (Pin12) -- OLED SCL
|
||||
|
||||
// I2C config for Microchip 24AA02E64 DEVEUI unique address
|
||||
//#define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64
|
||||
//#define MCP_24AA02E64_MAC_ADDRESS 0xF8 // Memory adress of unique deveui 64 bits
|
@ -24,5 +24,5 @@
|
||||
|
||||
// Hardware pin definitions for TTGOv1 Board with OLED SSD1306 I2C Display
|
||||
#define OLED_RST GPIO_NUM_16 // ESP32 GPIO16 (Pin16) -- SD1306 Reset
|
||||
#define OLED_SDA GPIO_NUM_4 // ESP32 GPIO4 (Pin4) -- SD1306 Data
|
||||
#define OLED_SCL GPIO_NUM_15 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
|
||||
#define I2C_SDA GPIO_NUM_4 // ESP32 GPIO4 (Pin4) -- SD1306 Data
|
||||
#define I2C_SCL GPIO_NUM_15 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
|
||||
|
@ -25,8 +25,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 GPIO21 -- SD1306 D1+D2
|
||||
#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
|
||||
#define I2C_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2
|
||||
#define I2C_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
|
||||
|
||||
/* source:
|
||||
https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-2/11973
|
||||
|
@ -1,69 +0,0 @@
|
||||
/* Hardware related definitions for TTGO V2.1 Board
|
||||
/ ATTENTION: check your board version!
|
||||
/ Different versions are on the market which need different settings in this file:
|
||||
/ - without label -> use settings (2)
|
||||
/ - labeled V1.5 on pcb -> use settings (2)
|
||||
/ - labeled V1.6 on pcb -> use settings (1)
|
||||
/ Choose the right configuration below
|
||||
*/
|
||||
|
||||
/*
|
||||
// (1) settings for board labeled "T3_V1.6" on pcb
|
||||
|
||||
#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 HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
#define HAS_LED GPIO_NUM_25 // green on board LED
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
|
||||
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||
|
||||
// re-define pin definitions of pins_arduino.h
|
||||
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input
|
||||
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input
|
||||
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output
|
||||
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input
|
||||
|
||||
// non arduino pin definitions
|
||||
#define RST GPIO_NUM_23 // ESP32 GPIO23 <-> HPD13A RESET
|
||||
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0
|
||||
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 <-> HPDIO1 <-> HPD13A IO1
|
||||
#define DIO2 GPIO_NUM_32 // ESP32 GPIO32 <-> HPDIO2 <-> HPD13A IO2
|
||||
|
||||
// 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 GPIO21 -- SD1306 D1+D2
|
||||
#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
|
||||
|
||||
*/
|
||||
|
||||
// (2) settings for boards without label on pcb, or labeled v1.5 on pcb
|
||||
|
||||
#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 HAS_LED NOT_A_PIN // no usable LED on board
|
||||
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
#define DISPLAY_FLIP 1 // rotated display
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
|
||||
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||
|
||||
// re-define pin definitions of pins_arduino.h
|
||||
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input
|
||||
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input
|
||||
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output
|
||||
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input
|
||||
|
||||
// non arduino pin definitions
|
||||
#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN (old board)
|
||||
//#define RST GPIO_NUM_12 // (boards labeled v1.5)
|
||||
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0
|
||||
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 <-> HPDIO1 <-> HPD13A IO1
|
||||
#define DIO2 GPIO_NUM_32 // ESP32 GPIO32 <-> HPDIO2 <-> HPD13A IO2
|
||||
|
||||
// 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 GPIO21 -- SD1306 D1+D2
|
||||
#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
|
30
src/hal/ttgov21new.h
Normal file
30
src/hal/ttgov21new.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* Hardware related definitions for TTGO V2.1 Board
|
||||
// ATTENTION: check your board version!
|
||||
// This settings are for boards labeled v1.6 on pcb, NOT for v1.5 or older
|
||||
*/
|
||||
|
||||
#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 HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
#define HAS_LED GPIO_NUM_25 // green on board LED
|
||||
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
|
||||
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||
|
||||
// re-define pin definitions of pins_arduino.h
|
||||
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input
|
||||
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input
|
||||
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output
|
||||
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input
|
||||
|
||||
// non arduino pin definitions
|
||||
#define RST GPIO_NUM_23 // ESP32 GPIO23 <-> HPD13A RESET
|
||||
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0
|
||||
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 <-> HPDIO1 <-> HPD13A IO1
|
||||
#define DIO2 GPIO_NUM_32 // ESP32 GPIO32 <-> HPDIO2 <-> HPD13A IO2
|
||||
|
||||
// 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 I2C_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2
|
||||
#define I2C_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
|
33
src/hal/ttgov21old.h
Normal file
33
src/hal/ttgov21old.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* Hardware related definitions for TTGO V2.1 Board
|
||||
// ATTENTION: check your board version!
|
||||
// This settings are for boards without label on pcb, or labeled v1.5 on pcb
|
||||
*/
|
||||
|
||||
#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 HAS_LED NOT_A_PIN // no usable LED on board
|
||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
|
||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||
//#define DISPLAY_FLIP 1 // rotated display
|
||||
//#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
|
||||
//#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||
|
||||
// re-define pin definitions of pins_arduino.h
|
||||
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input
|
||||
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input
|
||||
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output
|
||||
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input
|
||||
|
||||
// non arduino pin definitions
|
||||
#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN (old board)
|
||||
//#define RST GPIO_NUM_12 // (boards labeled v1.5)
|
||||
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0
|
||||
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 <-> HPDIO1 <-> HPD13A IO1
|
||||
#define DIO2 GPIO_NUM_32 // ESP32 GPIO32 <-> HPDIO2 <-> HPD13A IO2
|
||||
|
||||
// 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 I2C_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2
|
||||
#define I2C_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
|
@ -34,9 +34,9 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "hash.h"
|
||||
|
||||
uint32_t rokkit(const char *data, int len) {
|
||||
uint32_t IRAM_ATTR rokkit(const char *data, int len) {
|
||||
uint32_t hash, tmp;
|
||||
int rem;
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
#ifndef _HASH_H
|
||||
#define _HASH_H
|
||||
|
||||
uint32_t rokkit(const char *data, int len);
|
||||
#include <Arduino.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#endif
|
||||
uint32_t IRAM_ATTR rokkit(const char *data, int len);
|
||||
|
||||
#endif
|
74
src/irqhandler.cpp
Normal file
74
src/irqhandler.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "irqhandler.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
// irq handler task, handles all our application level interrupts
|
||||
void irqHandler(void *pvParameters) {
|
||||
|
||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||
|
||||
uint32_t InterruptStatus;
|
||||
|
||||
// task remains in blocked state until it is notified by an irq
|
||||
for (;;) {
|
||||
xTaskNotifyWait(
|
||||
0x00, // Don't clear any bits on entry
|
||||
ULONG_MAX, // Clear all bits on exit
|
||||
&InterruptStatus, // Receives the notification value
|
||||
portMAX_DELAY); // wait forever (missing error handling here...)
|
||||
|
||||
// button pressed?
|
||||
#ifdef HAS_BUTTON
|
||||
if (InterruptStatus & BUTTON_IRQ)
|
||||
readButton();
|
||||
#endif
|
||||
|
||||
// display needs refresh?
|
||||
#ifdef HAS_DISPLAY
|
||||
if (InterruptStatus & DISPLAY_IRQ)
|
||||
refreshtheDisplay();
|
||||
#endif
|
||||
|
||||
// are cyclic tasks due?
|
||||
if (InterruptStatus & CYCLIC_IRQ)
|
||||
doHousekeeping();
|
||||
|
||||
// is time to send the payload?
|
||||
if (InterruptStatus & SENDPAYLOAD_IRQ)
|
||||
sendPayload();
|
||||
}
|
||||
vTaskDelete(NULL); // shoud never be reached
|
||||
}
|
||||
|
||||
// esp32 hardware timer triggered interrupt service routines
|
||||
// they notify the irq handler task
|
||||
|
||||
void IRAM_ATTR ChannelSwitchIRQ() {
|
||||
xTaskNotifyGive(wifiSwitchTask);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
void IRAM_ATTR homeCycleIRQ() {
|
||||
xTaskNotifyFromISR(irqHandlerTask, CYCLIC_IRQ, eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
void IRAM_ATTR SendCycleIRQ() {
|
||||
xTaskNotifyFromISR(irqHandlerTask, SENDPAYLOAD_IRQ, eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
void IRAM_ATTR DisplayIRQ() {
|
||||
xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
void IRAM_ATTR ButtonIRQ() {
|
||||
xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
#endif
|
28
src/irqhandler.h
Normal file
28
src/irqhandler.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef _IRQHANDLER_H
|
||||
#define _IRQHANDLER_H
|
||||
|
||||
#define DISPLAY_IRQ 0x01
|
||||
#define BUTTON_IRQ 0x02
|
||||
#define SENDPAYLOAD_IRQ 0x04
|
||||
#define CYCLIC_IRQ 0x08
|
||||
|
||||
#include "globals.h"
|
||||
#include "cyclic.h"
|
||||
#include "senddata.h"
|
||||
|
||||
void irqHandler(void *pvParameters);
|
||||
void IRAM_ATTR ChannelSwitchIRQ();
|
||||
void IRAM_ATTR homeCycleIRQ();
|
||||
void IRAM_ATTR SendCycleIRQ();
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
#include "display.h"
|
||||
void IRAM_ATTR DisplayIRQ();
|
||||
#endif
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
#include "button.h"
|
||||
void IRAM_ATTR ButtonIRQ();
|
||||
#endif
|
||||
|
||||
#endif
|
106
src/led.cpp
106
src/led.cpp
@ -6,6 +6,8 @@ led_states LEDState = LED_OFF; // LED state global for state machine
|
||||
led_states previousLEDState =
|
||||
LED_ON; // This will force LED to be off at boot since State is OFF
|
||||
|
||||
TaskHandle_t ledLoopTask;
|
||||
|
||||
uint16_t LEDColor = COLOR_NONE, LEDBlinkDuration = 0; // state machine variables
|
||||
unsigned long LEDBlinkStarted = 0; // When (in millis() led blink started)
|
||||
|
||||
@ -94,69 +96,75 @@ void blink_LED(uint16_t set_color, uint16_t set_blinkduration) {
|
||||
LEDState = LED_ON; // Let main set LED on
|
||||
}
|
||||
|
||||
void led_loop() {
|
||||
// Custom blink running always have priority other LoRaWAN led management
|
||||
if (LEDBlinkStarted && LEDBlinkDuration) {
|
||||
// Custom blink is finished, let this order, avoid millis() overflow
|
||||
if ((millis() - LEDBlinkStarted) >= LEDBlinkDuration) {
|
||||
// Led becomes off, and stop blink
|
||||
LEDState = LED_OFF;
|
||||
LEDBlinkStarted = 0;
|
||||
LEDBlinkDuration = 0;
|
||||
LEDColor = COLOR_NONE;
|
||||
void ledLoop(void *parameter) {
|
||||
while (1) {
|
||||
// Custom blink running always have priority other LoRaWAN led management
|
||||
if (LEDBlinkStarted && LEDBlinkDuration) {
|
||||
// Custom blink is finished, let this order, avoid millis() overflow
|
||||
if ((millis() - LEDBlinkStarted) >= LEDBlinkDuration) {
|
||||
// Led becomes off, and stop blink
|
||||
LEDState = LED_OFF;
|
||||
LEDBlinkStarted = 0;
|
||||
LEDBlinkDuration = 0;
|
||||
LEDColor = COLOR_NONE;
|
||||
} else {
|
||||
// In case of LoRaWAN led management blinked off
|
||||
LEDState = LED_ON;
|
||||
}
|
||||
// No custom blink, check LoRaWAN state
|
||||
} else {
|
||||
// In case of LoRaWAN led management blinked off
|
||||
LEDState = LED_ON;
|
||||
}
|
||||
// No custom blink, check LoRaWAN state
|
||||
} else {
|
||||
|
||||
#ifdef HAS_LORA
|
||||
// LED indicators for viusalizing LoRaWAN state
|
||||
if (LMIC.opmode & (OP_JOINING | OP_REJOIN)) {
|
||||
LEDColor = COLOR_YELLOW;
|
||||
// quick blink 20ms on each 1/5 second
|
||||
LEDState = ((millis() % 200) < 20) ? LED_ON : LED_OFF; // TX data pending
|
||||
} else if (LMIC.opmode & (OP_TXDATA | OP_TXRXPEND)) {
|
||||
LEDColor = COLOR_BLUE;
|
||||
// small blink 10ms on each 1/2sec (not when joining)
|
||||
LEDState = ((millis() % 500) < 10) ? LED_ON : LED_OFF;
|
||||
// This should not happen so indicate a problem
|
||||
} else if (LMIC.opmode &
|
||||
((OP_TXDATA | OP_TXRXPEND | OP_JOINING | OP_REJOIN) == 0)) {
|
||||
LEDColor = COLOR_RED;
|
||||
// heartbeat long blink 200ms on each 2 seconds
|
||||
LEDState = ((millis() % 2000) < 200) ? LED_ON : LED_OFF;
|
||||
} else
|
||||
// LED indicators for viusalizing LoRaWAN state
|
||||
if (LMIC.opmode & (OP_JOINING | OP_REJOIN)) {
|
||||
LEDColor = COLOR_YELLOW;
|
||||
// quick blink 20ms on each 1/5 second
|
||||
LEDState =
|
||||
((millis() % 200) < 20) ? LED_ON : LED_OFF; // TX data pending
|
||||
} else if (LMIC.opmode & (OP_TXDATA | OP_TXRXPEND)) {
|
||||
LEDColor = COLOR_BLUE;
|
||||
// small blink 10ms on each 1/2sec (not when joining)
|
||||
LEDState = ((millis() % 500) < 10) ? LED_ON : LED_OFF;
|
||||
// This should not happen so indicate a problem
|
||||
} else if (LMIC.opmode &
|
||||
((OP_TXDATA | OP_TXRXPEND | OP_JOINING | OP_REJOIN) == 0)) {
|
||||
LEDColor = COLOR_RED;
|
||||
// heartbeat long blink 200ms on each 2 seconds
|
||||
LEDState = ((millis() % 2000) < 200) ? LED_ON : LED_OFF;
|
||||
} else
|
||||
#endif // HAS_LORA
|
||||
{
|
||||
// led off
|
||||
LEDColor = COLOR_NONE;
|
||||
LEDState = LED_OFF;
|
||||
{
|
||||
// led off
|
||||
LEDColor = COLOR_NONE;
|
||||
LEDState = LED_OFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
// led need to change state? avoid digitalWrite() for nothing
|
||||
if (LEDState != previousLEDState) {
|
||||
if (LEDState == LED_ON) {
|
||||
rgb_set_color(LEDColor);
|
||||
// led need to change state? avoid digitalWrite() for nothing
|
||||
if (LEDState != previousLEDState) {
|
||||
if (LEDState == LED_ON) {
|
||||
rgb_set_color(LEDColor);
|
||||
|
||||
#ifdef LED_ACTIVE_LOW
|
||||
digitalWrite(HAS_LED, LOW);
|
||||
digitalWrite(HAS_LED, LOW);
|
||||
#else
|
||||
digitalWrite(HAS_LED, HIGH);
|
||||
digitalWrite(HAS_LED, HIGH);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
rgb_set_color(COLOR_NONE);
|
||||
} else {
|
||||
rgb_set_color(COLOR_NONE);
|
||||
|
||||
#ifdef LED_ACTIVE_LOW
|
||||
digitalWrite(HAS_LED, HIGH);
|
||||
digitalWrite(HAS_LED, HIGH);
|
||||
#else
|
||||
digitalWrite(HAS_LED, LOW);
|
||||
digitalWrite(HAS_LED, LOW);
|
||||
#endif
|
||||
}
|
||||
previousLEDState = LEDState;
|
||||
}
|
||||
previousLEDState = LEDState;
|
||||
}
|
||||
}; // led_loop()
|
||||
// give yield to CPU
|
||||
vTaskDelay(2 / portTICK_PERIOD_MS);
|
||||
} // while(1)
|
||||
vTaskDelete(NULL); // shoud never be reached
|
||||
}; // ledloop()
|
||||
|
||||
#endif // #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
|
@ -31,9 +31,11 @@ struct RGBColor {
|
||||
|
||||
enum led_states { LED_OFF, LED_ON };
|
||||
|
||||
extern TaskHandle_t ledLoopTask;
|
||||
|
||||
// Exported Functions
|
||||
void rgb_set_color(uint16_t hue);
|
||||
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
|
||||
void led_loop();
|
||||
void ledLoop(void *parameter);
|
||||
|
||||
#endif
|
@ -1,16 +1,14 @@
|
||||
#ifdef HAS_LORA
|
||||
|
||||
// Basic Config
|
||||
#include "globals.h"
|
||||
#include "rcommand.h"
|
||||
|
||||
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||
#include <Wire.h> // Needed for 24AA02E64, does not hurt anything if included and not used
|
||||
#endif
|
||||
#include "lorawan.h"
|
||||
|
||||
// Local logging Tag
|
||||
static const char TAG[] = "lora";
|
||||
|
||||
osjob_t sendjob;
|
||||
QueueHandle_t LoraSendQueue;
|
||||
|
||||
// LMIC enhanced Pin mapping
|
||||
const lmic_pinmap lmic_pins = {.mosi = PIN_SPI_MOSI,
|
||||
.miso = PIN_SPI_MISO,
|
||||
@ -37,6 +35,27 @@ void gen_lora_deveui(uint8_t *pdeveui) {
|
||||
}
|
||||
}
|
||||
|
||||
/* new version, does it with well formed mac according IEEE spec, but is
|
||||
breaking change
|
||||
// DevEUI generator using devices's MAC address
|
||||
void gen_lora_deveui(uint8_t *pdeveui) {
|
||||
uint8_t *p = pdeveui, dmac[6];
|
||||
ESP_ERROR_CHECK(esp_efuse_mac_get_default(dmac));
|
||||
// deveui is LSB, we reverse it so TTN DEVEUI display
|
||||
// will remain the same as MAC address
|
||||
// MAC is 6 bytes, devEUI 8, set middle 2 ones
|
||||
// to an arbitrary value
|
||||
*p++ = dmac[5];
|
||||
*p++ = dmac[4];
|
||||
*p++ = dmac[3];
|
||||
*p++ = 0xfe;
|
||||
*p++ = 0xff;
|
||||
*p++ = dmac[2];
|
||||
*p++ = dmac[1];
|
||||
*p++ = dmac[0];
|
||||
}
|
||||
*/
|
||||
|
||||
// Function to do a byte swap in a byte array
|
||||
void RevBytes(unsigned char *b, size_t c) {
|
||||
u1_t i;
|
||||
@ -77,29 +96,34 @@ void os_getDevEui(u1_t *buf) {
|
||||
void get_hard_deveui(uint8_t *pdeveui) {
|
||||
// read DEVEUI from Microchip 24AA02E64 2Kb serial eeprom if present
|
||||
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||
|
||||
uint8_t i2c_ret;
|
||||
|
||||
// Init this just in case, no more to 100KHz
|
||||
Wire.begin(OLED_SDA, OLED_SCL, 100000);
|
||||
Wire.begin(I2C_SDA, I2C_SCL, 100000);
|
||||
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
||||
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
||||
i2c_ret = Wire.endTransmission();
|
||||
// check if device seen on i2c bus
|
||||
|
||||
// check if device was seen on i2c bus
|
||||
if (i2c_ret == 0) {
|
||||
char deveui[32] = "";
|
||||
uint8_t data;
|
||||
|
||||
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
||||
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(MCP_24AA02E64_I2C_ADDRESS, 8);
|
||||
while (Wire.available()) {
|
||||
data = Wire.read();
|
||||
sprintf(deveui + strlen(deveui), "%02X ", data);
|
||||
*pdeveui++ = data;
|
||||
}
|
||||
i2c_ret = Wire.endTransmission();
|
||||
ESP_LOGI(TAG, "Serial EEPROM 24AA02E64 found, read DEVEUI %s", deveui);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Serial EEPROM 24AA02E64 not found ret=%d", i2c_ret);
|
||||
}
|
||||
ESP_LOGI(TAG, "Serial EEPROM found, read DEVEUI %s", deveui);
|
||||
} else
|
||||
ESP_LOGI(TAG, "Could not read DEVEUI from serial EEPROM");
|
||||
|
||||
// Set back to 400KHz to speed up OLED
|
||||
Wire.setClock(400000);
|
||||
#endif // MCP 24AA02E64
|
||||
@ -183,6 +207,9 @@ void onEvent(ev_t ev) {
|
||||
// the library)
|
||||
switch_lora(cfg.lorasf, cfg.txpower);
|
||||
|
||||
// kickoff first send job
|
||||
os_setCallback(&sendjob, lora_send);
|
||||
|
||||
// show effective LoRa parameters after join
|
||||
ESP_LOGI(TAG, "ADR=%d, SF=%d, TXPOWER=%d", cfg.adrmode, cfg.lorasf,
|
||||
cfg.txpower);
|
||||
@ -196,11 +223,9 @@ void onEvent(ev_t ev) {
|
||||
|
||||
if (LMIC.dataLen) {
|
||||
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d",
|
||||
LMIC.dataLen, LMIC.rssi, (signed char)LMIC.snr / 4);
|
||||
// LMIC.snr = SNR twos compliment [dB] * 4
|
||||
// LMIC.rssi = RSSI [dBm] (-196...+63)
|
||||
LMIC.dataLen, LMIC.rssi, (signed char)LMIC.snr);
|
||||
sprintf(display_line6, "RSSI %d SNR %d", LMIC.rssi,
|
||||
(signed char)LMIC.snr / 4);
|
||||
(signed char)LMIC.snr);
|
||||
|
||||
// check if command is received on command port, then call interpreter
|
||||
if ((LMIC.txrxFlags & TXRX_PORT) &&
|
||||
@ -222,17 +247,6 @@ void onEvent(ev_t ev) {
|
||||
|
||||
} // onEvent()
|
||||
|
||||
// LMIC FreeRTos Task
|
||||
void lorawan_loop(void *pvParameters) {
|
||||
|
||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||
|
||||
while (1) {
|
||||
os_runloop_once(); // execute LMIC jobs
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to assign LoRa datarates to numeric spreadfactor values
|
||||
void switch_lora(uint8_t sf, uint8_t tx) {
|
||||
if (tx > 20)
|
||||
@ -280,4 +294,25 @@ void switch_lora(uint8_t sf, uint8_t tx) {
|
||||
}
|
||||
}
|
||||
|
||||
void lora_send(osjob_t *job) {
|
||||
MessageBuffer_t SendBuffer;
|
||||
// Check if there is a pending TX/RX job running, if yes don't eat data
|
||||
// since it cannot be sent right now
|
||||
if ((LMIC.opmode & (OP_JOINING | OP_REJOIN | OP_TXDATA | OP_POLL)) != 0) {
|
||||
// waiting for LoRa getting ready
|
||||
} else {
|
||||
if (xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) {
|
||||
// SendBuffer gets struct MessageBuffer with next payload from queue
|
||||
LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message,
|
||||
SendBuffer.MessageSize, (cfg.countermode & 0x02));
|
||||
ESP_LOGI(TAG, "%d bytes sent to LoRa", SendBuffer.MessageSize);
|
||||
sprintf(display_line7, "PACKET QUEUED");
|
||||
}
|
||||
}
|
||||
// reschedule job every 0,5 - 1 sec. including a bit of random to prevent
|
||||
// systematic collisions
|
||||
os_setTimedCallback(job, os_getTime() + 500 + ms2osticks(random(500)),
|
||||
lora_send);
|
||||
}
|
||||
|
||||
#endif // HAS_LORA
|
@ -1,11 +1,21 @@
|
||||
#ifndef _LORAWAN_H
|
||||
#define _LORAWAN_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "rcommand.h"
|
||||
|
||||
// LMIC-Arduino LoRaWAN Stack
|
||||
#include <lmic.h>
|
||||
#include <hal/hal.h>
|
||||
#include "loraconf.h"
|
||||
|
||||
// Needed for 24AA02E64, does not hurt anything if included and not used
|
||||
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
extern QueueHandle_t LoraSendQueue;
|
||||
|
||||
void onEvent(ev_t ev);
|
||||
void gen_lora_deveui(uint8_t *pdeveui);
|
||||
void RevBytes(unsigned char *b, size_t c);
|
||||
@ -14,7 +24,7 @@ void os_getDevKey(u1_t *buf);
|
||||
void os_getArtEui(u1_t *buf);
|
||||
void os_getDevEui(u1_t *buf);
|
||||
void showLoraKeys(void);
|
||||
void lorawan_loop(void *pvParameters);
|
||||
void switch_lora(uint8_t sf, uint8_t tx);
|
||||
void lora_send(osjob_t *job);
|
||||
|
||||
#endif
|
@ -11,8 +11,8 @@ static const char TAG[] = "main";
|
||||
|
||||
uint16_t salt;
|
||||
|
||||
uint16_t reset_salt(void) {
|
||||
salt = random(65536); // get new 16bit random for salting hashes
|
||||
uint16_t get_salt(void) {
|
||||
salt = (uint16_t)random(65536); // get new 16bit random for salting hashes
|
||||
return salt;
|
||||
}
|
||||
|
||||
@ -71,8 +71,8 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) {
|
||||
// https://en.wikipedia.org/wiki/MAC_Address_Anonymization
|
||||
|
||||
snprintf(buff, sizeof(buff), "%08X",
|
||||
addr2int + (uint32_t)salt); // convert usigned 32-bit salted MAC to
|
||||
// 8 digit hex string
|
||||
addr2int + (uint32_t)salt); // convert usigned 32-bit salted MAC
|
||||
// to 8 digit hex string
|
||||
hashedmac = rokkit(&buff[3], 5); // hash MAC last string value, use 5 chars
|
||||
// to fit hash in uint16_t container
|
||||
auto newmac = macs.insert(hashedmac); // add hashed MAC, if new unique
|
||||
@ -81,7 +81,6 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) {
|
||||
|
||||
// Count only if MAC was not yet seen
|
||||
if (added) {
|
||||
|
||||
// increment counter and one blink led
|
||||
if (sniff_type == MAC_SNIFF_WIFI) {
|
||||
macs_wifi++; // increment Wifi MACs counter
|
||||
|
@ -12,7 +12,7 @@
|
||||
#define MAC_SNIFF_WIFI 0
|
||||
#define MAC_SNIFF_BLE 1
|
||||
|
||||
uint16_t reset_salt(void);
|
||||
uint16_t get_salt(void);
|
||||
uint64_t macConvert(uint8_t *paddr);
|
||||
bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type);
|
||||
void printKey(const char *name, const uint8_t *key, uint8_t len, bool lsb);
|
||||
|
418
src/main.cpp
418
src/main.cpp
@ -21,38 +21,42 @@ 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.
|
||||
|
||||
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
|
||||
|
||||
Uused tasks and timers:
|
||||
|
||||
Task Core Prio Purpose
|
||||
====================================================================================
|
||||
wifiloop 0 4 rotates wifi channels
|
||||
ledloop 0 3 blinks LEDs
|
||||
gpsloop 0 2 reads data from GPS over serial or i2c
|
||||
spiloop 0 2 reads/writes data on spi interface
|
||||
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
|
||||
|
||||
looptask 1 1 arduino core -> runs the LMIC LoRa stack
|
||||
irqhandler 1 1 executes tasks triggered by irq
|
||||
IDLE 1 0 ESP32 arduino scheduler
|
||||
|
||||
ESP32 hardware timers
|
||||
==========================
|
||||
0 Trigger display refresh
|
||||
1 Trigger Wifi channel switch
|
||||
2 Trigger send payload cycle
|
||||
3 Trigger housekeeping cycle
|
||||
|
||||
*/
|
||||
|
||||
// Basic Config
|
||||
#include "globals.h"
|
||||
#include "main.h"
|
||||
|
||||
configData_t cfg; // struct holds current device configuration
|
||||
char display_line6[16], display_line7[16]; // display buffers
|
||||
uint8_t channel = 0; // channel rotation counter
|
||||
uint16_t macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
||||
batt_voltage = 0; // globals for display
|
||||
uint8_t volatile channel = 0; // channel rotation counter
|
||||
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
||||
batt_voltage = 0; // globals for display
|
||||
|
||||
// hardware timer for cyclic tasks
|
||||
hw_timer_t *channelSwitch = NULL, *displaytimer = NULL, *sendCycle = NULL,
|
||||
*homeCycle = NULL;
|
||||
|
||||
// this variables will be changed in the ISR, and read in main loop
|
||||
volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, SendCycleTimerIRQ = 0,
|
||||
DisplayTimerIRQ = 0, HomeCycleIRQ = 0;
|
||||
|
||||
// RTos send queues for payload transmit
|
||||
#ifdef HAS_LORA
|
||||
QueueHandle_t LoraSendQueue;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPI
|
||||
QueueHandle_t SPISendQueue;
|
||||
#endif
|
||||
|
||||
portMUX_TYPE timerMux =
|
||||
portMUX_INITIALIZER_UNLOCKED; // sync main loop and ISR when modifying IRQ
|
||||
// handler shared variables
|
||||
hw_timer_t *channelSwitch, *sendCycle, *homeCycle, *displaytimer; // irq tasks
|
||||
TaskHandle_t irqHandlerTask, wifiSwitchTask;
|
||||
|
||||
std::set<uint16_t> macs; // container holding unique MAC adress hashes
|
||||
|
||||
@ -62,17 +66,17 @@ PayloadConvert payload(PAYLOAD_BUFFER_SIZE);
|
||||
// local Tag for logging
|
||||
static const char TAG[] = "main";
|
||||
|
||||
/* begin Aruino SETUP
|
||||
* ------------------------------------------------------------ */
|
||||
|
||||
void setup() {
|
||||
|
||||
// disable the default wifi logging
|
||||
esp_log_level_set("wifi", ESP_LOG_NONE);
|
||||
|
||||
char features[100] = "";
|
||||
|
||||
// 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;
|
||||
(*((uint32_t volatile *)ETS_UNCACHED_ADDR((DR_REG_RTCCNTL_BASE + 0xd4)))) = 0;
|
||||
#endif
|
||||
|
||||
// setup debug output or silence device
|
||||
@ -85,11 +89,108 @@ void setup() {
|
||||
esp_log_set_vprintf(redirect_log);
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Starting %s v%s", PROGNAME, PROGVERSION);
|
||||
// read (and initialize on first run) runtime settings from NVRAM
|
||||
loadConfig(); // includes initialize if necessary
|
||||
|
||||
// initialize system event handler for wifi task, needed for
|
||||
// wifi_sniffer_init()
|
||||
esp_event_loop_init(NULL, NULL);
|
||||
// initialize leds
|
||||
#if (HAS_LED != NOT_A_PIN)
|
||||
pinMode(HAS_LED, OUTPUT);
|
||||
strcat_P(features, " LED");
|
||||
#endif
|
||||
#ifdef HAS_RGB_LED
|
||||
rgb_set_color(COLOR_PINK);
|
||||
strcat_P(features, " RGB");
|
||||
#endif
|
||||
|
||||
// initialize wifi antenna
|
||||
#ifdef HAS_ANTENNA_SWITCH
|
||||
strcat_P(features, " ANT");
|
||||
antenna_init();
|
||||
antenna_select(cfg.wifiant);
|
||||
#endif
|
||||
|
||||
// switch off bluetooth, if not compiled
|
||||
#ifdef BLECOUNTER
|
||||
strcat_P(features, " BLE");
|
||||
#else
|
||||
bool btstop = btStop();
|
||||
#endif
|
||||
|
||||
// initialize battery status
|
||||
#ifdef HAS_BATTERY_PROBE
|
||||
strcat_P(features, " BATT");
|
||||
calibrate_voltage();
|
||||
batt_voltage = read_voltage();
|
||||
#endif
|
||||
|
||||
#ifdef USE_OTA
|
||||
strcat_P(features, " OTA");
|
||||
// reboot to firmware update mode if ota trigger switch is set
|
||||
if (cfg.runmode == 1) {
|
||||
cfg.runmode = 0;
|
||||
saveConfig();
|
||||
start_ota_update();
|
||||
}
|
||||
#endif
|
||||
|
||||
// initialize button
|
||||
#ifdef HAS_BUTTON
|
||||
strcat_P(features, " BTN_");
|
||||
#ifdef BUTTON_PULLUP
|
||||
strcat_P(features, "PU");
|
||||
// install button interrupt (pullup mode)
|
||||
pinMode(HAS_BUTTON, INPUT_PULLUP);
|
||||
#else
|
||||
strcat_P(features, "PD");
|
||||
// install button interrupt (pulldown mode)
|
||||
pinMode(HAS_BUTTON, INPUT_PULLDOWN);
|
||||
#endif // BUTTON_PULLUP
|
||||
#endif // HAS_BUTTON
|
||||
|
||||
// initialize gps
|
||||
#ifdef HAS_GPS
|
||||
strcat_P(features, " GPS");
|
||||
#endif
|
||||
|
||||
// initialize LoRa
|
||||
#ifdef HAS_LORA
|
||||
strcat_P(features, " LORA");
|
||||
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||
if (LoraSendQueue == 0) {
|
||||
ESP_LOGE(TAG, "Could not create LORA send queue. Aborting.");
|
||||
exit(0);
|
||||
} else
|
||||
ESP_LOGI(TAG, "LORA send queue created, size %d Bytes",
|
||||
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
|
||||
|
||||
ESP_LOGI(TAG, "Starting LMIC...");
|
||||
os_init(); // initialize lmic run-time environment on core 1
|
||||
LMIC_reset(); // initialize lmic MAC
|
||||
LMIC_setClockError(MAX_CLOCK_ERROR * 1 /
|
||||
100); // This tells LMIC to make the receive windows
|
||||
// bigger, in case your clock is 1% faster or slower.
|
||||
|
||||
LMIC_startJoining(); // start joining
|
||||
|
||||
#endif
|
||||
|
||||
// initialize SPI
|
||||
#ifdef HAS_SPI
|
||||
strcat_P(features, " SPI");
|
||||
SPISendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||
if (SPISendQueue == 0) {
|
||||
ESP_LOGE(TAG, "Could not create SPI send queue. Aborting.");
|
||||
exit(0);
|
||||
} else
|
||||
ESP_LOGI(TAG, "SPI send queue created, size %d Bytes",
|
||||
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
|
||||
#endif
|
||||
|
||||
#ifdef VENDORFILTER
|
||||
strcat_P(features, " OUIFLT");
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Starting %s v%s", PRODUCTNAME, PROGVERSION);
|
||||
|
||||
// print chip information on startup if in verbose mode
|
||||
#ifdef VERBOSE
|
||||
@ -112,126 +213,36 @@ void setup() {
|
||||
|
||||
#endif // verbose
|
||||
|
||||
// read settings from NVRAM
|
||||
loadConfig(); // includes initialize if necessary
|
||||
|
||||
#ifdef VENDORFILTER
|
||||
strcat_P(features, " OUIFLT");
|
||||
#endif
|
||||
|
||||
// initialize LoRa
|
||||
#ifdef HAS_LORA
|
||||
strcat_P(features, " LORA");
|
||||
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||
if (LoraSendQueue == 0) {
|
||||
ESP_LOGE(TAG, "Could not create LORA send queue. Aborting.");
|
||||
exit(0);
|
||||
} else
|
||||
ESP_LOGI(TAG, "LORA send queue created, size %d Bytes",
|
||||
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
|
||||
#endif
|
||||
|
||||
// initialize SPI
|
||||
#ifdef HAS_SPI
|
||||
strcat_P(features, " SPI");
|
||||
SPISendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||
if (SPISendQueue == 0) {
|
||||
ESP_LOGE(TAG, "Could not create SPI send queue. Aborting.");
|
||||
exit(0);
|
||||
} else
|
||||
ESP_LOGI(TAG, "SPI send queue created, size %d Bytes",
|
||||
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
|
||||
#endif
|
||||
|
||||
// initialize led
|
||||
#if (HAS_LED != NOT_A_PIN)
|
||||
pinMode(HAS_LED, OUTPUT);
|
||||
strcat_P(features, " LED");
|
||||
#endif
|
||||
|
||||
#ifdef HAS_RGB_LED
|
||||
rgb_set_color(COLOR_PINK);
|
||||
strcat_P(features, " RGB");
|
||||
#endif
|
||||
|
||||
// initialize button
|
||||
#ifdef HAS_BUTTON
|
||||
strcat_P(features, " BTN_");
|
||||
#ifdef BUTTON_PULLUP
|
||||
strcat_P(features, "PU");
|
||||
// install button interrupt (pullup mode)
|
||||
pinMode(HAS_BUTTON, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
|
||||
#else
|
||||
strcat_P(features, "PD");
|
||||
// install button interrupt (pulldown mode)
|
||||
pinMode(HAS_BUTTON, INPUT_PULLDOWN);
|
||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING);
|
||||
#endif // BUTTON_PULLUP
|
||||
#endif // HAS_BUTTON
|
||||
|
||||
// initialize wifi antenna
|
||||
#ifdef HAS_ANTENNA_SWITCH
|
||||
strcat_P(features, " ANT");
|
||||
antenna_init();
|
||||
antenna_select(cfg.wifiant);
|
||||
#endif
|
||||
|
||||
// switch off bluetooth on esp32 module, if not compiled
|
||||
#ifdef BLECOUNTER
|
||||
strcat_P(features, " BLE");
|
||||
#else
|
||||
bool btstop = btStop();
|
||||
#endif
|
||||
|
||||
// initialize gps
|
||||
#ifdef HAS_GPS
|
||||
strcat_P(features, " GPS");
|
||||
#endif
|
||||
|
||||
// initialize battery status
|
||||
#ifdef HAS_BATTERY_PROBE
|
||||
strcat_P(features, " BATT");
|
||||
calibrate_voltage();
|
||||
batt_voltage = read_voltage();
|
||||
#endif
|
||||
|
||||
// initialize display
|
||||
#ifdef HAS_DISPLAY
|
||||
strcat_P(features, " OLED");
|
||||
DisplayState = cfg.screenon;
|
||||
init_display(PROGNAME, PROGVERSION);
|
||||
init_display(PRODUCTNAME, PROGVERSION);
|
||||
|
||||
// setup display refresh trigger IRQ using esp32 hardware timer
|
||||
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
|
||||
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// setup channel rotation trigger IRQ using esp32 hardware timer 1
|
||||
channelSwitch = timerBegin(1, 800, true);
|
||||
timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true);
|
||||
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 1000, true);
|
||||
timerAlarmEnable(channelSwitch);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// setup channel rotation trigger IRQ using esp32 hardware timer 1
|
||||
channelSwitch = timerBegin(1, 800, true);
|
||||
timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true);
|
||||
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 1000, true);
|
||||
|
||||
// show payload encoder
|
||||
#if PAYLOAD_ENCODER == 1
|
||||
@ -252,89 +263,106 @@ void setup() {
|
||||
#ifdef VERBOSE
|
||||
showLoraKeys();
|
||||
#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);
|
||||
// join network
|
||||
LMIC_startJoining();
|
||||
|
||||
// start lmic runloop in rtos task on core 1
|
||||
// (note: arduino main loop runs on core 1, too)
|
||||
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
|
||||
|
||||
ESP_LOGI(TAG, "Starting Lora task on core 1");
|
||||
xTaskCreatePinnedToCore(lorawan_loop, "loraloop", 2048, (void *)1,
|
||||
(5 | portPRIVILEGE_BIT), NULL, 1);
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
||||
// start BLE scan callback if BLE function is enabled in NVRAM configuration
|
||||
#ifdef BLECOUNTER
|
||||
if (cfg.blescan) {
|
||||
ESP_LOGI(TAG, "Starting BLE task on core 1");
|
||||
ESP_LOGI(TAG, "Starting Bluetooth...");
|
||||
start_BLEscan();
|
||||
}
|
||||
#endif
|
||||
|
||||
// start wifi in monitor mode and start channel rotation task on core 0
|
||||
ESP_LOGI(TAG, "Starting Wifi task on core 0");
|
||||
ESP_LOGI(TAG, "Starting Wifi...");
|
||||
wifi_sniffer_init();
|
||||
// initialize salt value using esp_random() called by random() in
|
||||
// arduino-esp32 core. Note: do this *after* wifi has started, since function
|
||||
// gets it's seed from RF noise
|
||||
reset_salt(); // get new 16bit for salting hashes
|
||||
xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1,
|
||||
NULL, 0);
|
||||
// arduino-esp32 core. Note: do this *after* wifi has started, since
|
||||
// function gets it's seed from RF noise
|
||||
get_salt(); // get new 16bit for salting hashes
|
||||
|
||||
#ifdef HAS_GPS
|
||||
ESP_LOGI(TAG, "Starting GPSloop...");
|
||||
xTaskCreatePinnedToCore(gps_loop, // task function
|
||||
"gpsloop", // name of task
|
||||
1024, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
2, // priority of the task
|
||||
&GpsTask, // task handle
|
||||
0); // CPU core
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPI
|
||||
ESP_LOGI(TAG, "Starting SPIloop...");
|
||||
xTaskCreatePinnedToCore(spi_loop, // task function
|
||||
"spiloop", // name of task
|
||||
2048, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
2, // priority of the task
|
||||
&SpiTask, // task handle
|
||||
0); // CPU core
|
||||
#endif
|
||||
|
||||
// start state machine
|
||||
ESP_LOGI(TAG, "Starting IRQ Handler...");
|
||||
xTaskCreatePinnedToCore(irqHandler, // task function
|
||||
"irqhandler", // name of task
|
||||
2048, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
1, // priority of the task
|
||||
&irqHandlerTask, // task handle
|
||||
1); // CPU core
|
||||
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
// start led loop
|
||||
ESP_LOGI(TAG, "Starting LEDloop...");
|
||||
xTaskCreatePinnedToCore(ledLoop, // task function
|
||||
"ledloop", // name of task
|
||||
1024, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
3, // priority of the task
|
||||
&ledLoopTask, // task handle
|
||||
0); // CPU core
|
||||
#endif
|
||||
|
||||
// start wifi channel rotation task
|
||||
ESP_LOGI(TAG, "Starting Wifi Channel rotation...");
|
||||
xTaskCreatePinnedToCore(switchWifiChannel, // task function
|
||||
"wifiloop", // name of task
|
||||
2048, // stack size of task
|
||||
NULL, // parameter of the task
|
||||
4, // priority of the task
|
||||
&wifiSwitchTask, // task handle
|
||||
0); // CPU core
|
||||
|
||||
// start timer triggered interrupts
|
||||
ESP_LOGI(TAG, "Starting Interrupts...");
|
||||
#ifdef HAS_DISPLAY
|
||||
timerAlarmEnable(displaytimer);
|
||||
#endif
|
||||
timerAlarmEnable(sendCycle);
|
||||
timerAlarmEnable(homeCycle);
|
||||
timerAlarmEnable(channelSwitch);
|
||||
|
||||
// start button interrupt
|
||||
#ifdef HAS_BUTTON
|
||||
#ifdef BUTTON_PULLUP
|
||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
|
||||
#else
|
||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING);
|
||||
#endif
|
||||
#endif // HAS_BUTTON
|
||||
|
||||
} // setup()
|
||||
|
||||
/* end Arduino SETUP
|
||||
* ------------------------------------------------------------ */
|
||||
|
||||
/* begin Arduino main loop
|
||||
* ------------------------------------------------------ */
|
||||
|
||||
void loop() {
|
||||
|
||||
while (1) {
|
||||
// state machine for switching display, LED, button, housekeeping, senddata
|
||||
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
led_loop();
|
||||
#ifdef HAS_LORA
|
||||
os_runloop_once(); // execute lmic scheduled jobs and events
|
||||
#endif
|
||||
vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU
|
||||
}
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
readButton();
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
updateDisplay();
|
||||
#endif
|
||||
|
||||
// check housekeeping cycle and if expired do homework
|
||||
checkHousekeeping();
|
||||
// check send queue and process it
|
||||
processSendBuffer();
|
||||
// check send cycle and enqueue payload if cycle is expired
|
||||
sendPayload();
|
||||
// reset watchdog
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
|
||||
} // loop()
|
||||
}
|
||||
|
||||
/* end Arduino main loop
|
||||
* ------------------------------------------------------------ */
|
||||
vTaskDelete(NULL); // shoud never be reached
|
||||
}
|
17
src/main.h
17
src/main.h
@ -1,15 +1,16 @@
|
||||
#ifndef _MAIN_H
|
||||
#define _MAIN_H
|
||||
|
||||
//#include "led.h"
|
||||
#include "macsniff.h"
|
||||
#include "wifiscan.h"
|
||||
#include "configmanager.h"
|
||||
#include "senddata.h"
|
||||
#include "cyclic.h"
|
||||
#include "beacon_array.h"
|
||||
|
||||
#include <esp_spi_flash.h> // needed for reading ESP32 chip attributes
|
||||
#include <esp_event_loop.h> // needed for Wifi event handler
|
||||
#include <esp32-hal-timer.h> // needed for timers
|
||||
|
||||
#include "globals.h"
|
||||
#include "wifiscan.h"
|
||||
#include "configmanager.h"
|
||||
#include "cyclic.h"
|
||||
#include "beacon_array.h"
|
||||
#include "ota.h"
|
||||
#include "irqhandler.h"
|
||||
|
||||
#endif
|
373
src/ota.cpp
Normal file
373
src/ota.cpp
Normal file
@ -0,0 +1,373 @@
|
||||
#ifdef USE_OTA
|
||||
|
||||
/*
|
||||
Parts of this code:
|
||||
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "ota.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE);
|
||||
|
||||
// Connection port (HTTPS)
|
||||
const int port = 443;
|
||||
|
||||
// Connection timeout
|
||||
const uint32_t RESPONSE_TIMEOUT_MS = 5000;
|
||||
|
||||
// Variables to validate firmware content
|
||||
int volatile contentLength = 0;
|
||||
bool volatile isValidContentType = false;
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
// helper function to extract header value from header
|
||||
inline String getHeaderValue(String header, String headerName) {
|
||||
return header.substring(strlen(headerName.c_str()));
|
||||
}
|
||||
|
||||
void start_ota_update() {
|
||||
|
||||
/*
|
||||
// check battery status if we can before doing ota
|
||||
#ifdef HAS_BATTERY_PROBE
|
||||
if (!batt_sufficient()) {
|
||||
ESP_LOGW(TAG, "Battery voltage %dmV too low for OTA", batt_voltage);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
// turn on LED
|
||||
#if (HAS_LED != NOT_A_PIN)
|
||||
#ifdef LED_ACTIVE_LOW
|
||||
digitalWrite(HAS_LED, LOW);
|
||||
#else
|
||||
digitalWrite(HAS_LED, HIGH);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
u8x8.begin();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.clear();
|
||||
#ifdef DISPLAY_FLIP
|
||||
u8x8.setFlipMode(1);
|
||||
#endif
|
||||
u8x8.setInverseFont(1);
|
||||
u8x8.print("SOFTWARE UPDATE \n");
|
||||
u8x8.setInverseFont(0);
|
||||
u8x8.print("WiFi connect ..\n");
|
||||
u8x8.print("Has Update? ..\n");
|
||||
u8x8.print("Fetching ..\n");
|
||||
u8x8.print("Downloading ..\n");
|
||||
u8x8.print("Rebooting ..");
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Starting Wifi OTA update");
|
||||
display(1, "**", WIFI_SSID);
|
||||
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||
|
||||
int i = WIFI_MAX_TRY;
|
||||
|
||||
while (i--) {
|
||||
ESP_LOGI(TAG, "Trying to connect to %s", WIFI_SSID);
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
break;
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
if (i >= 0) {
|
||||
ESP_LOGI(TAG, "Connected to %s", WIFI_SSID);
|
||||
display(1, "OK", "WiFi connected");
|
||||
do_ota_update(); // gets and flashes new firmware
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Could not connect to %s, rebooting.", WIFI_SSID);
|
||||
display(1, " E", "no WiFi connect");
|
||||
}
|
||||
|
||||
display(5, "**", ""); // mark line rebooting
|
||||
|
||||
// turn off LED
|
||||
#if (HAS_LED != NOT_A_PIN)
|
||||
#ifdef LED_ACTIVE_LOW
|
||||
digitalWrite(HAS_LED, HIGH);
|
||||
#else
|
||||
digitalWrite(HAS_LED, LOW);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
ESP.restart();
|
||||
|
||||
} // start_ota_update
|
||||
|
||||
void do_ota_update() {
|
||||
char buf[17];
|
||||
|
||||
// Fetch the latest firmware version
|
||||
ESP_LOGI(TAG, "Checking latest firmware version on server...");
|
||||
display(2, "**", "checking version");
|
||||
const String latest = bintray.getLatestVersion();
|
||||
|
||||
if (latest.length() == 0) {
|
||||
ESP_LOGI(
|
||||
TAG,
|
||||
"Could not load info about the latest firmware. Rebooting to runmode.");
|
||||
display(2, " E", "file not found");
|
||||
return;
|
||||
} else if (version_compare(latest, cfg.version) <= 0) {
|
||||
ESP_LOGI(TAG, "Current firmware is up to date. Rebooting to runmode.");
|
||||
display(2, "NO", "no update found");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "New firmware version v%s available. Downloading...",
|
||||
latest.c_str());
|
||||
display(2, "OK", latest.c_str());
|
||||
|
||||
display(3, "**", "");
|
||||
String firmwarePath = bintray.getBinaryPath(latest);
|
||||
if (!firmwarePath.endsWith(".bin")) {
|
||||
ESP_LOGI(TAG, "Unsupported binary format, OTA update cancelled.");
|
||||
display(3, " E", "file type error");
|
||||
return;
|
||||
}
|
||||
|
||||
String currentHost = bintray.getStorageHost();
|
||||
String prevHost = currentHost;
|
||||
|
||||
WiFiClientSecure client;
|
||||
client.setCACert(bintray.getCertificate(currentHost));
|
||||
|
||||
if (!client.connect(currentHost.c_str(), port)) {
|
||||
ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str());
|
||||
display(3, " E", "connection lost");
|
||||
return;
|
||||
}
|
||||
|
||||
bool redirect = true;
|
||||
while (redirect) {
|
||||
if (currentHost != prevHost) {
|
||||
client.stop();
|
||||
client.setCACert(bintray.getCertificate(currentHost));
|
||||
if (!client.connect(currentHost.c_str(), port)) {
|
||||
ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s",
|
||||
currentHost.c_str());
|
||||
display(3, " E", "server error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Requesting %s", firmwarePath.c_str());
|
||||
|
||||
client.print(String("GET ") + firmwarePath + " HTTP/1.1\r\n");
|
||||
client.print(String("Host: ") + currentHost + "\r\n");
|
||||
client.print("Cache-Control: no-cache\r\n");
|
||||
client.print("Connection: close\r\n\r\n");
|
||||
|
||||
unsigned long timeout = millis();
|
||||
while (client.available() == 0) {
|
||||
if (millis() - timeout > RESPONSE_TIMEOUT_MS) {
|
||||
ESP_LOGI(TAG, "Client Timeout.");
|
||||
display(3, " E", "client timeout");
|
||||
client.stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (client.available()) {
|
||||
String line = client.readStringUntil('\n');
|
||||
// Check if the line is end of headers by removing space symbol
|
||||
line.trim();
|
||||
// if the the line is empty, this is the end of the headers
|
||||
if (!line.length()) {
|
||||
break; // proceed to OTA update
|
||||
}
|
||||
|
||||
// Check allowed HTTP responses
|
||||
if (line.startsWith("HTTP/1.1")) {
|
||||
if (line.indexOf("200") > 0) {
|
||||
ESP_LOGI(TAG, "Got 200 status code from server. Proceeding to "
|
||||
"firmware flashing");
|
||||
redirect = false;
|
||||
} else if (line.indexOf("302") > 0) {
|
||||
ESP_LOGI(TAG, "Got 302 status code from server. Redirecting to the "
|
||||
"new address");
|
||||
redirect = true;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Could not get a valid firmware url.");
|
||||
// Unexptected HTTP response. Retry or skip update?
|
||||
redirect = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Extracting new redirect location
|
||||
if (line.startsWith("Location: ")) {
|
||||
String newUrl = getHeaderValue(line, "Location: ");
|
||||
ESP_LOGI(TAG, "Got new url: %s", newUrl.c_str());
|
||||
newUrl.remove(0, newUrl.indexOf("//") + 2);
|
||||
currentHost = newUrl.substring(0, newUrl.indexOf('/'));
|
||||
newUrl.remove(newUrl.indexOf(currentHost), currentHost.length());
|
||||
firmwarePath = newUrl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Checking headers
|
||||
if (line.startsWith("Content-Length: ")) {
|
||||
contentLength =
|
||||
atoi((getHeaderValue(line, "Content-Length: ")).c_str());
|
||||
ESP_LOGI(TAG, "Got %d bytes from server", contentLength);
|
||||
}
|
||||
|
||||
if (line.startsWith("Content-Type: ")) {
|
||||
String contentType = getHeaderValue(line, "Content-Type: ");
|
||||
ESP_LOGI(TAG, "Got %s payload", contentType.c_str());
|
||||
if (contentType == "application/octet-stream") {
|
||||
isValidContentType = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
display(3, "OK", ""); // line download
|
||||
|
||||
// check whether we have everything for OTA update
|
||||
if (contentLength && isValidContentType) {
|
||||
|
||||
size_t written, current, size;
|
||||
|
||||
if (Update.begin(contentLength)) {
|
||||
#ifdef HAS_DISPLAY
|
||||
// register callback function for showing progress while streaming data
|
||||
Update.onProgress(&show_progress);
|
||||
#endif
|
||||
int i = FLASH_MAX_TRY;
|
||||
while ((i--) && (written != contentLength)) {
|
||||
|
||||
ESP_LOGI(TAG,
|
||||
"Starting OTA update, attempt %u of %u. This will take some "
|
||||
"time to complete...",
|
||||
FLASH_MAX_TRY - i, FLASH_MAX_TRY);
|
||||
display(4, "**", "writing...");
|
||||
|
||||
written = Update.writeStream(client);
|
||||
|
||||
if (written == contentLength) {
|
||||
ESP_LOGI(TAG, "Written %u bytes successfully", written);
|
||||
snprintf(buf, 17, "%u kB Done!", (uint16_t)(written / 1024));
|
||||
display(4, "OK", buf);
|
||||
break;
|
||||
} else {
|
||||
ESP_LOGI(TAG,
|
||||
"Written only %u of %u bytes, OTA update attempt cancelled.",
|
||||
written, contentLength);
|
||||
}
|
||||
}
|
||||
|
||||
if (Update.end()) {
|
||||
|
||||
if (Update.isFinished()) {
|
||||
ESP_LOGI(
|
||||
TAG,
|
||||
"OTA update completed. Rebooting to runmode with new version.");
|
||||
client.stop();
|
||||
return;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished "
|
||||
"properly.");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(TAG, "An error occurred. Error #: %d", Update.getError());
|
||||
snprintf(buf, 17, "Error #: %d", Update.getError());
|
||||
display(4, " E", buf);
|
||||
}
|
||||
|
||||
} else {
|
||||
ESP_LOGI(TAG, "There isn't enough space to start OTA update");
|
||||
display(4, " E", "disk full");
|
||||
client.flush();
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(TAG,
|
||||
"There was no valid content in the response from the OTA server!");
|
||||
display(4, " E", "response error");
|
||||
client.flush();
|
||||
}
|
||||
ESP_LOGI(TAG,
|
||||
"OTA update failed. Rebooting to runmode with current version.");
|
||||
client.stop();
|
||||
} // do_ota_update
|
||||
|
||||
void display(const uint8_t row, const std::string status,
|
||||
const std::string msg) {
|
||||
#ifdef HAS_DISPLAY
|
||||
u8x8.setCursor(14, row);
|
||||
u8x8.print((status.substr(0, 2)).c_str());
|
||||
if (!msg.empty()) {
|
||||
u8x8.clearLine(7);
|
||||
u8x8.setCursor(0, 7);
|
||||
u8x8.print(msg.substr(0, 16).c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
// callback function to show download progress while streaming data
|
||||
void show_progress(size_t current, size_t size) {
|
||||
char buf[17];
|
||||
snprintf(buf, 17, "%-9lu (%3lu%%)", current, current * 100 / size);
|
||||
display(4, "**", buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
// helper function to compare two versions. Returns 1 if v2 is
|
||||
// smaller, -1 if v1 is smaller, 0 if equal
|
||||
|
||||
int version_compare(const String v1, const String v2) {
|
||||
// vnum stores each numeric part of version
|
||||
int vnum1 = 0, vnum2 = 0;
|
||||
|
||||
// loop until both string are processed
|
||||
for (int i = 0, j = 0; (i < v1.length() || j < v2.length());) {
|
||||
// storing numeric part of version 1 in vnum1
|
||||
while (i < v1.length() && v1[i] != '.') {
|
||||
vnum1 = vnum1 * 10 + (v1[i] - '0');
|
||||
i++;
|
||||
}
|
||||
|
||||
// storing numeric part of version 2 in vnum2
|
||||
while (j < v2.length() && v2[j] != '.') {
|
||||
vnum2 = vnum2 * 10 + (v2[j] - '0');
|
||||
j++;
|
||||
}
|
||||
|
||||
if (vnum1 > vnum2)
|
||||
return 1;
|
||||
if (vnum2 > vnum1)
|
||||
return -1;
|
||||
|
||||
// if equal, reset variables and go for next numeric
|
||||
// part
|
||||
vnum1 = vnum2 = 0;
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif // USE_OTA
|
25
src/ota.h
Normal file
25
src/ota.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef OTA_H
|
||||
#define OTA_H
|
||||
|
||||
#ifdef USE_OTA
|
||||
|
||||
#include "globals.h"
|
||||
#include "update.h"
|
||||
#include "battery.h"
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <BintrayClient.h>
|
||||
#include <string>
|
||||
|
||||
void do_ota_update();
|
||||
void start_ota_update();
|
||||
int version_compare(const String v1, const String v2);
|
||||
void display(const uint8_t row, const std::string status,
|
||||
const std::string msg);
|
||||
#ifdef HAS_DISPLAY
|
||||
void show_progress(size_t current, size_t size);
|
||||
#endif
|
||||
|
||||
#endif // USE_OTA
|
||||
|
||||
#endif // OTA_H
|
8
src/ota.sample.conf
Normal file
8
src/ota.sample.conf
Normal file
@ -0,0 +1,8 @@
|
||||
[ota]
|
||||
OTA_WIFI_SSID = MyHomeWifi
|
||||
OTA_WIFI_PASS = FooBar42!
|
||||
|
||||
[bintray]
|
||||
BINTRAY_USER = MyBintrayUser
|
||||
BINTRAY_REPO = MyBintrayRepo
|
||||
BINTRAY_API_TOKEN = 3894a7a51d70c6523c1b7479261c34845ebf7878
|
@ -4,12 +4,14 @@
|
||||
//
|
||||
// Note: After editing, before "build", use "clean" button in PlatformIO!
|
||||
|
||||
#define PRODUCTNAME "PAXCNT"
|
||||
|
||||
// Verbose enables serial output
|
||||
#define VERBOSE 1 // comment out to silence the device, for mute use build option
|
||||
|
||||
// Payload send cycle and encoding
|
||||
#define SEND_SECS 30 // payload send cycle [seconds/2] -> 60 sec.
|
||||
#define PAYLOAD_ENCODER 1 // payload encoder: 1=Plain, 2=Packed, 3=CayenneLPP dynamic, 4=CayenneLPP packed
|
||||
#define PAYLOAD_ENCODER 2 // 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
|
||||
@ -63,6 +65,12 @@
|
||||
#define DISPLAYREFRESH_MS 40 // OLED refresh cycle in ms [default = 40] -> 1000/40 = 25 frames per second
|
||||
#define HOMECYCLE 30 // house keeping cycle in seconds [default = 30 secs]
|
||||
|
||||
// OTA settings
|
||||
#define USE_OTA 1 // Comment out to disable OTA update
|
||||
#define WIFI_MAX_TRY 20 // maximum number of wifi connect attempts for OTA update [default = 20]
|
||||
#define FLASH_MAX_TRY 3 // maximum number of attempts for writing update binary to flash [default = 3]
|
||||
#define OTA_MIN_BATT 3700 // minimum battery level vor OTA [millivolt]
|
||||
|
||||
// LMIC settings
|
||||
// define hardware independent LMIC settings here, settings of standard library in /lmic/config.h will be ignored
|
||||
// define hardware specifics settings in platformio.ini as build_flag for hardware environment
|
||||
|
@ -52,8 +52,9 @@ void PayloadConvert::addConfig(configData_t value) {
|
||||
cursor += 10;
|
||||
}
|
||||
|
||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
||||
float cputemp, uint32_t mem) {
|
||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp,
|
||||
uint32_t mem, uint8_t reset1, uint8_t reset2) {
|
||||
|
||||
buffer[cursor++] = highByte(voltage);
|
||||
buffer[cursor++] = lowByte(voltage);
|
||||
buffer[cursor++] = (byte)((uptime & 0xFF00000000000000) >> 56);
|
||||
@ -69,6 +70,8 @@ void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
||||
buffer[cursor++] = (byte)((mem & 0x00FF0000) >> 16);
|
||||
buffer[cursor++] = (byte)((mem & 0x0000FF00) >> 8);
|
||||
buffer[cursor++] = (byte)((mem & 0x000000FF));
|
||||
buffer[cursor++] = (byte)(reset1);
|
||||
buffer[cursor++] = (byte)(reset2);
|
||||
}
|
||||
|
||||
#ifdef HAS_GPS
|
||||
@ -121,14 +124,17 @@ void PayloadConvert::addConfig(configData_t value) {
|
||||
value.screenon ? true : false, value.countermode ? true : false,
|
||||
value.blescan ? true : false, value.wifiant ? true : false,
|
||||
value.vendorfilter ? true : false, value.gpsmode ? true : false);
|
||||
writeVersion(value.version);
|
||||
}
|
||||
|
||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
||||
float cputemp, uint32_t mem) {
|
||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp,
|
||||
uint32_t mem, uint8_t reset1, uint8_t reset2) {
|
||||
writeUint16(voltage);
|
||||
writeUptime(uptime);
|
||||
writeUint8((byte)cputemp);
|
||||
writeUint32(mem);
|
||||
writeUint8(reset1);
|
||||
writeUint8(reset2);
|
||||
}
|
||||
|
||||
#ifdef HAS_GPS
|
||||
@ -155,6 +161,11 @@ void PayloadConvert::writeUptime(uint64_t uptime) {
|
||||
intToBytes(cursor, uptime, 8);
|
||||
}
|
||||
|
||||
void PayloadConvert::writeVersion(char * version) {
|
||||
memcpy(buffer + cursor, version, 10);
|
||||
cursor += 10;
|
||||
}
|
||||
|
||||
void PayloadConvert::writeLatLng(double latitude, double longitude) {
|
||||
intToBytes(cursor, latitude, 4);
|
||||
intToBytes(cursor, longitude, 4);
|
||||
@ -241,8 +252,8 @@ void PayloadConvert::addConfig(configData_t value) {
|
||||
buffer[cursor++] = value.adrmode;
|
||||
}
|
||||
|
||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime,
|
||||
float celsius, uint32_t mem) {
|
||||
void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float celsius,
|
||||
uint32_t mem, uint8_t reset1, uint8_t reset2) {
|
||||
uint16_t temp = celsius * 10;
|
||||
uint16_t volt = voltage / 10;
|
||||
#ifdef HAS_BATTERY_PROBE
|
||||
|
@ -35,7 +35,8 @@ public:
|
||||
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, uint32_t mem);
|
||||
void addStatus(uint16_t voltage, uint64_t uptime, float cputemp, uint32_t mem,
|
||||
uint8_t reset1, uint8_t reset2);
|
||||
void addAlarm(int8_t rssi, uint8_t message);
|
||||
#ifdef HAS_GPS
|
||||
void addGPS(gpsStatus_t value);
|
||||
@ -44,7 +45,6 @@ public:
|
||||
void addButton(uint8_t value);
|
||||
#endif
|
||||
|
||||
|
||||
#if PAYLOAD_ENCODER == 1 // format plain
|
||||
|
||||
private:
|
||||
@ -64,6 +64,7 @@ private:
|
||||
void writeUint8(uint8_t i);
|
||||
void writeHumidity(float humidity);
|
||||
void writeTemperature(float temperature);
|
||||
void writeVersion(char * version);
|
||||
void writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, bool g,
|
||||
bool h);
|
||||
|
||||
@ -77,7 +78,6 @@ private:
|
||||
#else
|
||||
#error "No valid payload converter defined"
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
extern PayloadConvert payload;
|
||||
|
@ -18,7 +18,7 @@ void set_reset(uint8_t val[]) {
|
||||
case 1: // reset MAC counter
|
||||
ESP_LOGI(TAG, "Remote command: reset MAC counter");
|
||||
reset_counters(); // clear macs
|
||||
reset_salt(); // get new salt
|
||||
get_salt(); // get new salt
|
||||
sprintf(display_line6, "Reset counter");
|
||||
break;
|
||||
case 2: // reset device to factory settings
|
||||
@ -31,6 +31,16 @@ void set_reset(uint8_t val[]) {
|
||||
sprintf(display_line6, "Queue reset");
|
||||
flushQueues();
|
||||
break;
|
||||
case 9: // reset and ask for software update via Wifi OTA
|
||||
ESP_LOGI(TAG, "Remote command: software update via Wifi");
|
||||
#ifdef USE_OTA
|
||||
sprintf(display_line6, "Software update");
|
||||
cfg.runmode = 1;
|
||||
#else
|
||||
sprintf(display_line6, "Software update not implemented");
|
||||
#endif // USE_OTA
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(TAG, "Remote command: reset called with invalid parameter(s)");
|
||||
}
|
||||
@ -203,7 +213,8 @@ void get_status(uint8_t val[]) {
|
||||
#endif
|
||||
payload.reset();
|
||||
payload.addStatus(voltage, uptime() / 1000, temperatureRead(),
|
||||
ESP.getFreeHeap());
|
||||
ESP.getFreeHeap(), rtc_get_reset_reason(0),
|
||||
rtc_get_reset_reason(1));
|
||||
SendData(STATUSPORT);
|
||||
};
|
||||
|
||||
@ -221,14 +232,14 @@ void get_gps(uint8_t val[]) {
|
||||
|
||||
// assign previously defined functions to set of numeric remote commands
|
||||
// format: opcode, function, #bytes params,
|
||||
// flag (1 = do make settings persistent / 0 = don't)
|
||||
// flag (true = do make settings persistent / false = don't)
|
||||
//
|
||||
cmd_t table[] = {
|
||||
{0x01, set_rssi, 1, true}, {0x02, set_countmode, 1, true},
|
||||
{0x03, set_gps, 1, true}, {0x04, set_display, 1, true},
|
||||
{0x05, set_lorasf, 1, true}, {0x06, set_lorapower, 1, true},
|
||||
{0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 1, true},
|
||||
{0x09, set_reset, 1, false}, {0x0a, set_sendcycle, 1, true},
|
||||
{0x09, set_reset, 1, true}, {0x0a, set_sendcycle, 1, true},
|
||||
{0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true},
|
||||
{0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true},
|
||||
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "configmanager.h"
|
||||
#include "lorawan.h"
|
||||
#include "macsniff.h"
|
||||
#include <rom/rtc.h>
|
||||
|
||||
// table of remote commands and assigned functions
|
||||
typedef struct {
|
||||
|
@ -29,80 +29,38 @@ void SendData(uint8_t port) {
|
||||
// clear counter if not in cumulative counter mode
|
||||
if ((port == COUNTERPORT) && (cfg.countermode != 1)) {
|
||||
reset_counters(); // clear macs container and reset all counters
|
||||
reset_salt(); // get new salt for salting hashes
|
||||
get_salt(); // get new salt for salting hashes
|
||||
ESP_LOGI(TAG, "Counter cleared");
|
||||
}
|
||||
} // SendData
|
||||
|
||||
// cyclic called function to prepare payload to send
|
||||
// interrupt triggered function to prepare payload to send
|
||||
void sendPayload() {
|
||||
|
||||
if (SendCycleTimerIRQ) {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
SendCycleTimerIRQ = 0;
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
|
||||
// append counter data to payload
|
||||
payload.reset();
|
||||
payload.addCount(macs_wifi, cfg.blescan ? macs_ble : 0);
|
||||
// append GPS data, if present
|
||||
// append counter data to payload
|
||||
payload.reset();
|
||||
payload.addCount(macs_wifi, cfg.blescan ? macs_ble : 0);
|
||||
// append GPS data, if present
|
||||
|
||||
#ifdef HAS_GPS
|
||||
// show NMEA data in debug mode, useful for debugging GPS on board
|
||||
// connection
|
||||
ESP_LOGD(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d",
|
||||
gps.passedChecksum(), gps.failedChecksum(),
|
||||
gps.sentencesWithFix());
|
||||
// log GPS position if we have a fix and gps data mode is enabled
|
||||
if ((cfg.gpsmode) && (gps.location.isValid())) {
|
||||
gps_read();
|
||||
payload.addGPS(gps_status);
|
||||
ESP_LOGD(TAG, "lat=%.6f | lon=%.6f | %u Sats | HDOP=%.1f | Altitude=%um",
|
||||
gps_status.latitude / (float)1e6,
|
||||
gps_status.longitude / (float)1e6, gps_status.satellites,
|
||||
gps_status.hdop / (float)100, gps_status.altitude);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "No valid GPS position or GPS data mode disabled");
|
||||
}
|
||||
#endif
|
||||
SendData(COUNTERPORT);
|
||||
}
|
||||
} // sendpayload()
|
||||
|
||||
// interrupt handler used for payload send cycle timer
|
||||
void IRAM_ATTR SendCycleIRQ() {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
SendCycleTimerIRQ++;
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
}
|
||||
|
||||
// cyclic called function to eat data from RTos send queues and transmit it
|
||||
void processSendBuffer() {
|
||||
|
||||
MessageBuffer_t SendBuffer;
|
||||
|
||||
#ifdef HAS_LORA
|
||||
// Check if there is a pending TX/RX job running
|
||||
if ((LMIC.opmode & (OP_JOINING | OP_REJOIN | OP_TXDATA | OP_POLL)) != 0) {
|
||||
// LoRa Busy -> don't eat data from queue, since it cannot be sent
|
||||
// show NMEA data in debug mode, useful for debugging GPS on board
|
||||
// connection
|
||||
ESP_LOGD(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d",
|
||||
gps.passedChecksum(), gps.failedChecksum(), gps.sentencesWithFix());
|
||||
// log GPS position if we have a fix and gps data mode is enabled
|
||||
if ((cfg.gpsmode) && (gps.location.isValid())) {
|
||||
gps_read();
|
||||
payload.addGPS(gps_status);
|
||||
ESP_LOGD(TAG, "lat=%.6f | lon=%.6f | %u Sats | HDOP=%.1f | Altitude=%um",
|
||||
gps_status.latitude / (float)1e6,
|
||||
gps_status.longitude / (float)1e6, gps_status.satellites,
|
||||
gps_status.hdop / (float)100, gps_status.altitude);
|
||||
} else {
|
||||
if (xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) {
|
||||
// SendBuffer gets struct MessageBuffer with next payload from queue
|
||||
LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message,
|
||||
SendBuffer.MessageSize, (cfg.countermode & 0x02));
|
||||
ESP_LOGI(TAG, "%d bytes sent to LoRa", SendBuffer.MessageSize);
|
||||
sprintf(display_line7, "PACKET QUEUED");
|
||||
}
|
||||
ESP_LOGD(TAG, "No valid GPS position or GPS data mode disabled");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPI
|
||||
if (xQueueReceive(SPISendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) {
|
||||
ESP_LOGI(TAG, "%d bytes sent to SPI", SendBuffer.MessageSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // processSendBuffer
|
||||
SendData(COUNTERPORT);
|
||||
} // sendpayload()
|
||||
|
||||
void flushQueues() {
|
||||
#ifdef HAS_LORA
|
||||
|
@ -3,8 +3,7 @@
|
||||
|
||||
void SendData(uint8_t port);
|
||||
void sendPayload(void);
|
||||
void SendCycleIRQ(void);
|
||||
void processSendBuffer(void);
|
||||
void checkSendQueues(void);
|
||||
void flushQueues();
|
||||
|
||||
#endif // _SENDDATA_H_
|
30
src/spi.cpp
Normal file
30
src/spi.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#ifdef HAS_SPI
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
MessageBuffer_t SendBuffer;
|
||||
|
||||
QueueHandle_t SPISendQueue;
|
||||
TaskHandle_t SpiTask;
|
||||
|
||||
// SPI feed Task
|
||||
void spi_loop(void *pvParameters) {
|
||||
|
||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(SPISendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) {
|
||||
ESP_LOGI(TAG, "%d bytes sent to SPI", SendBuffer.MessageSize);
|
||||
}
|
||||
vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU
|
||||
|
||||
} // end of infinite loop
|
||||
|
||||
vTaskDelete(NULL); // shoud never be reached
|
||||
|
||||
} // spi_loop()
|
||||
|
||||
#endif // HAS_SPI
|
9
src/spi.h
Normal file
9
src/spi.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _SPI_H
|
||||
#define _SPI_H
|
||||
|
||||
extern TaskHandle_t SpiTask;
|
||||
extern QueueHandle_t SPISendQueue;
|
||||
|
||||
void spi_loop(void *pvParameters);
|
||||
|
||||
#endif
|
354
src/update.cpp
Normal file
354
src/update.cpp
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
|
||||
this file copied from esp32-arduino library and patched, see PR
|
||||
https://github.com/espressif/arduino-esp32/pull/1886
|
||||
|
||||
*/
|
||||
|
||||
#include "update.h"
|
||||
#include "Arduino.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
static const char * _err2str(uint8_t _error){
|
||||
if(_error == UPDATE_ERROR_OK){
|
||||
return ("No Error");
|
||||
} else if(_error == UPDATE_ERROR_WRITE){
|
||||
return ("Flash Write Failed");
|
||||
} else if(_error == UPDATE_ERROR_ERASE){
|
||||
return ("Flash Erase Failed");
|
||||
} else if(_error == UPDATE_ERROR_READ){
|
||||
return ("Flash Read Failed");
|
||||
} else if(_error == UPDATE_ERROR_SPACE){
|
||||
return ("Not Enough Space");
|
||||
} else if(_error == UPDATE_ERROR_SIZE){
|
||||
return ("Bad Size Given");
|
||||
} else if(_error == UPDATE_ERROR_STREAM){
|
||||
return ("Stream Read Timeout");
|
||||
} else if(_error == UPDATE_ERROR_MD5){
|
||||
return ("MD5 Check Failed");
|
||||
} else if(_error == UPDATE_ERROR_MAGIC_BYTE){
|
||||
return ("Wrong Magic Byte");
|
||||
} else if(_error == UPDATE_ERROR_ACTIVATE){
|
||||
return ("Could Not Activate The Firmware");
|
||||
} else if(_error == UPDATE_ERROR_NO_PARTITION){
|
||||
return ("Partition Could Not be Found");
|
||||
} else if(_error == UPDATE_ERROR_BAD_ARGUMENT){
|
||||
return ("Bad Argument");
|
||||
} else if(_error == UPDATE_ERROR_ABORT){
|
||||
return ("Aborted");
|
||||
}
|
||||
return ("UNKNOWN");
|
||||
}
|
||||
|
||||
static bool _partitionIsBootable(const esp_partition_t* partition){
|
||||
uint8_t buf[4];
|
||||
if(!partition){
|
||||
return false;
|
||||
}
|
||||
if(!ESP.flashRead(partition->address, (uint32_t*)buf, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(buf[0] != ESP_IMAGE_HEADER_MAGIC) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _enablePartition(const esp_partition_t* partition){
|
||||
uint8_t buf[4];
|
||||
if(!partition){
|
||||
return false;
|
||||
}
|
||||
if(!ESP.flashRead(partition->address, (uint32_t*)buf, 4)) {
|
||||
return false;
|
||||
}
|
||||
buf[0] = ESP_IMAGE_HEADER_MAGIC;
|
||||
|
||||
return ESP.flashWrite(partition->address, (uint32_t*)buf, 4);
|
||||
}
|
||||
|
||||
UpdateClass::UpdateClass()
|
||||
: _error(0)
|
||||
, _buffer(0)
|
||||
, _bufferLen(0)
|
||||
, _size(0)
|
||||
, _progress_callback(NULL)
|
||||
, _progress(0)
|
||||
, _command(U_FLASH)
|
||||
, _partition(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
UpdateClass& UpdateClass::onProgress(THandlerFunction_Progress fn) {
|
||||
_progress_callback = fn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void UpdateClass::_reset() {
|
||||
if (_buffer)
|
||||
delete[] _buffer;
|
||||
_buffer = 0;
|
||||
_bufferLen = 0;
|
||||
_progress = 0;
|
||||
_size = 0;
|
||||
_command = U_FLASH;
|
||||
}
|
||||
|
||||
bool UpdateClass::canRollBack(){
|
||||
if(_buffer){ //Update is running
|
||||
return false;
|
||||
}
|
||||
const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL);
|
||||
return _partitionIsBootable(partition);
|
||||
}
|
||||
|
||||
bool UpdateClass::rollBack(){
|
||||
if(_buffer){ //Update is running
|
||||
return false;
|
||||
}
|
||||
const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL);
|
||||
return _partitionIsBootable(partition) && !esp_ota_set_boot_partition(partition);
|
||||
}
|
||||
|
||||
bool UpdateClass::begin(size_t size, int command) {
|
||||
if(_size > 0){
|
||||
log_w("already running");
|
||||
return false;
|
||||
}
|
||||
|
||||
_reset();
|
||||
_error = 0;
|
||||
|
||||
if(size == 0) {
|
||||
_error = UPDATE_ERROR_SIZE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (command == U_FLASH) {
|
||||
_partition = esp_ota_get_next_update_partition(NULL);
|
||||
if(!_partition){
|
||||
_error = UPDATE_ERROR_NO_PARTITION;
|
||||
return false;
|
||||
}
|
||||
log_d("OTA Partition: %s", _partition->label);
|
||||
}
|
||||
else if (command == U_SPIFFS) {
|
||||
_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL);
|
||||
if(!_partition){
|
||||
_error = UPDATE_ERROR_NO_PARTITION;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
_error = UPDATE_ERROR_BAD_ARGUMENT;
|
||||
log_e("bad command %u", command);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(size == UPDATE_SIZE_UNKNOWN){
|
||||
size = _partition->size;
|
||||
} else if(size > _partition->size){
|
||||
_error = UPDATE_ERROR_SIZE;
|
||||
log_e("too large %u > %u", size, _partition->size);
|
||||
return false;
|
||||
}
|
||||
|
||||
//initialize
|
||||
_buffer = (uint8_t*)malloc(SPI_FLASH_SEC_SIZE);
|
||||
if(!_buffer){
|
||||
log_e("malloc failed");
|
||||
return false;
|
||||
}
|
||||
_size = size;
|
||||
_command = command;
|
||||
_md5.begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateClass::_abort(uint8_t err){
|
||||
_reset();
|
||||
_error = err;
|
||||
}
|
||||
|
||||
void UpdateClass::abort(){
|
||||
_abort(UPDATE_ERROR_ABORT);
|
||||
}
|
||||
|
||||
bool UpdateClass::_writeBuffer(){
|
||||
//first bytes of new firmware
|
||||
if(!_progress && _command == U_FLASH){
|
||||
//check magic
|
||||
if(_buffer[0] != ESP_IMAGE_HEADER_MAGIC){
|
||||
_abort(UPDATE_ERROR_MAGIC_BYTE);
|
||||
return false;
|
||||
}
|
||||
//remove magic byte from the firmware now and write it upon success
|
||||
//this ensures that partially written firmware will not be bootable
|
||||
_buffer[0] = 0xFF;
|
||||
}
|
||||
if(!ESP.flashEraseSector((_partition->address + _progress)/SPI_FLASH_SEC_SIZE)){
|
||||
_abort(UPDATE_ERROR_ERASE);
|
||||
return false;
|
||||
}
|
||||
if (!ESP.flashWrite(_partition->address + _progress, (uint32_t*)_buffer, _bufferLen)) {
|
||||
_abort(UPDATE_ERROR_WRITE);
|
||||
return false;
|
||||
}
|
||||
//restore magic or md5 will fail
|
||||
if(!_progress && _command == U_FLASH){
|
||||
_buffer[0] = ESP_IMAGE_HEADER_MAGIC;
|
||||
}
|
||||
_md5.add(_buffer, _bufferLen);
|
||||
_progress += _bufferLen;
|
||||
_bufferLen = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdateClass::_verifyHeader(uint8_t data) {
|
||||
if(_command == U_FLASH) {
|
||||
if(data != ESP_IMAGE_HEADER_MAGIC) {
|
||||
_abort(UPDATE_ERROR_MAGIC_BYTE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if(_command == U_SPIFFS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UpdateClass::_verifyEnd() {
|
||||
if(_command == U_FLASH) {
|
||||
if(!_enablePartition(_partition) || !_partitionIsBootable(_partition)) {
|
||||
_abort(UPDATE_ERROR_READ);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(esp_ota_set_boot_partition(_partition)){
|
||||
_abort(UPDATE_ERROR_ACTIVATE);
|
||||
return false;
|
||||
}
|
||||
_reset();
|
||||
return true;
|
||||
} else if(_command == U_SPIFFS) {
|
||||
_reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UpdateClass::setMD5(const char * expected_md5){
|
||||
if(strlen(expected_md5) != 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_target_md5 = expected_md5;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdateClass::end(bool evenIfRemaining){
|
||||
if(hasError() || _size == 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isFinished() && !evenIfRemaining){
|
||||
log_e("premature end: res:%u, pos:%u/%u\n", getError(), progress(), _size);
|
||||
_abort(UPDATE_ERROR_ABORT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(evenIfRemaining) {
|
||||
if(_bufferLen > 0) {
|
||||
_writeBuffer();
|
||||
}
|
||||
_size = progress();
|
||||
}
|
||||
|
||||
_md5.calculate();
|
||||
if(_target_md5.length()) {
|
||||
if(_target_md5 != _md5.toString()){
|
||||
_abort(UPDATE_ERROR_MD5);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return _verifyEnd();
|
||||
}
|
||||
|
||||
size_t UpdateClass::write(uint8_t *data, size_t len) {
|
||||
if(hasError() || !isRunning()){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(len > remaining()){
|
||||
_abort(UPDATE_ERROR_SPACE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t left = len;
|
||||
|
||||
while((_bufferLen + left) > SPI_FLASH_SEC_SIZE) {
|
||||
size_t toBuff = SPI_FLASH_SEC_SIZE - _bufferLen;
|
||||
memcpy(_buffer + _bufferLen, data + (len - left), toBuff);
|
||||
_bufferLen += toBuff;
|
||||
if(!_writeBuffer()){
|
||||
return len - left;
|
||||
}
|
||||
left -= toBuff;
|
||||
}
|
||||
memcpy(_buffer + _bufferLen, data + (len - left), left);
|
||||
_bufferLen += left;
|
||||
if(_bufferLen == remaining()){
|
||||
if(!_writeBuffer()){
|
||||
return len - left;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t UpdateClass::writeStream(Stream &data) {
|
||||
data.setTimeout(20000);
|
||||
size_t written = 0;
|
||||
size_t toRead = 0;
|
||||
if(hasError() || !isRunning())
|
||||
return 0;
|
||||
|
||||
if(!_verifyHeader(data.peek())) {
|
||||
_reset();
|
||||
return 0;
|
||||
}
|
||||
if (_progress_callback) {
|
||||
_progress_callback(0, _size);
|
||||
}
|
||||
while(remaining()) {
|
||||
toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen));
|
||||
if(toRead == 0) { //Timeout
|
||||
delay(100);
|
||||
toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen));
|
||||
if(toRead == 0) { //Timeout
|
||||
_abort(UPDATE_ERROR_STREAM);
|
||||
return written;
|
||||
}
|
||||
}
|
||||
_bufferLen += toRead;
|
||||
if((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer())
|
||||
return written;
|
||||
written += toRead;
|
||||
if(_progress_callback) {
|
||||
_progress_callback(_progress, _size);
|
||||
}
|
||||
}
|
||||
if(_progress_callback) {
|
||||
_progress_callback(_size, _size);
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
void UpdateClass::printError(Stream &out){
|
||||
out.println(_err2str(_error));
|
||||
}
|
||||
|
||||
UpdateClass Update;
|
181
src/update.h
Normal file
181
src/update.h
Normal file
@ -0,0 +1,181 @@
|
||||
#ifndef ESP8266UPDATER_H
|
||||
#define ESP8266UPDATER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <MD5Builder.h>
|
||||
#include <functional>
|
||||
#include "esp_partition.h"
|
||||
|
||||
#define UPDATE_ERROR_OK (0)
|
||||
#define UPDATE_ERROR_WRITE (1)
|
||||
#define UPDATE_ERROR_ERASE (2)
|
||||
#define UPDATE_ERROR_READ (3)
|
||||
#define UPDATE_ERROR_SPACE (4)
|
||||
#define UPDATE_ERROR_SIZE (5)
|
||||
#define UPDATE_ERROR_STREAM (6)
|
||||
#define UPDATE_ERROR_MD5 (7)
|
||||
#define UPDATE_ERROR_MAGIC_BYTE (8)
|
||||
#define UPDATE_ERROR_ACTIVATE (9)
|
||||
#define UPDATE_ERROR_NO_PARTITION (10)
|
||||
#define UPDATE_ERROR_BAD_ARGUMENT (11)
|
||||
#define UPDATE_ERROR_ABORT (12)
|
||||
|
||||
#define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
#define U_FLASH 0
|
||||
#define U_SPIFFS 100
|
||||
#define U_AUTH 200
|
||||
|
||||
class UpdateClass {
|
||||
public:
|
||||
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
|
||||
|
||||
UpdateClass();
|
||||
|
||||
/*
|
||||
This callback will be called when Update is receiving data
|
||||
*/
|
||||
UpdateClass& onProgress(THandlerFunction_Progress fn);
|
||||
|
||||
/*
|
||||
Call this to check the space needed for the update
|
||||
Will return false if there is not enough space
|
||||
*/
|
||||
bool begin(size_t size=UPDATE_SIZE_UNKNOWN, int command = U_FLASH);
|
||||
|
||||
/*
|
||||
Writes a buffer to the flash and increments the address
|
||||
Returns the amount written
|
||||
*/
|
||||
size_t write(uint8_t *data, size_t len);
|
||||
|
||||
/*
|
||||
Writes the remaining bytes from the Stream to the flash
|
||||
Uses readBytes() and sets UPDATE_ERROR_STREAM on timeout
|
||||
Returns the bytes written
|
||||
Should be equal to the remaining bytes when called
|
||||
Usable for slow streams like Serial
|
||||
*/
|
||||
size_t writeStream(Stream &data);
|
||||
|
||||
/*
|
||||
If all bytes are written
|
||||
this call will write the config to eboot
|
||||
and return true
|
||||
If there is already an update running but is not finished and !evenIfRemainanig
|
||||
or there is an error
|
||||
this will clear everything and return false
|
||||
the last error is available through getError()
|
||||
evenIfRemaining is helpfull when you update without knowing the final size first
|
||||
*/
|
||||
bool end(bool evenIfRemaining = false);
|
||||
|
||||
/*
|
||||
Aborts the running update
|
||||
*/
|
||||
void abort();
|
||||
|
||||
/*
|
||||
Prints the last error to an output stream
|
||||
*/
|
||||
void printError(Stream &out);
|
||||
|
||||
/*
|
||||
sets the expected MD5 for the firmware (hexString)
|
||||
*/
|
||||
bool setMD5(const char * expected_md5);
|
||||
|
||||
/*
|
||||
returns the MD5 String of the sucessfully ended firmware
|
||||
*/
|
||||
String md5String(void){ return _md5.toString(); }
|
||||
|
||||
/*
|
||||
populated the result with the md5 bytes of the sucessfully ended firmware
|
||||
*/
|
||||
void md5(uint8_t * result){ return _md5.getBytes(result); }
|
||||
|
||||
//Helpers
|
||||
uint8_t getError(){ return _error; }
|
||||
void clearError(){ _error = UPDATE_ERROR_OK; }
|
||||
bool hasError(){ return _error != UPDATE_ERROR_OK; }
|
||||
bool isRunning(){ return _size > 0; }
|
||||
bool isFinished(){ return _progress == _size; }
|
||||
size_t size(){ return _size; }
|
||||
size_t progress(){ return _progress; }
|
||||
size_t remaining(){ return _size - _progress; }
|
||||
|
||||
/*
|
||||
Template to write from objects that expose
|
||||
available() and read(uint8_t*, size_t) methods
|
||||
faster than the writeStream method
|
||||
writes only what is available
|
||||
*/
|
||||
template<typename T>
|
||||
size_t write(T &data){
|
||||
size_t written = 0;
|
||||
if (hasError() || !isRunning())
|
||||
return 0;
|
||||
|
||||
size_t available = data.available();
|
||||
while(available) {
|
||||
if(_bufferLen + available > remaining()){
|
||||
available = remaining() - _bufferLen;
|
||||
}
|
||||
if(_bufferLen + available > 4096) {
|
||||
size_t toBuff = 4096 - _bufferLen;
|
||||
data.read(_buffer + _bufferLen, toBuff);
|
||||
_bufferLen += toBuff;
|
||||
if(!_writeBuffer())
|
||||
return written;
|
||||
written += toBuff;
|
||||
} else {
|
||||
data.read(_buffer + _bufferLen, available);
|
||||
_bufferLen += available;
|
||||
written += available;
|
||||
if(_bufferLen == remaining()) {
|
||||
if(!_writeBuffer()) {
|
||||
return written;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(remaining() == 0)
|
||||
return written;
|
||||
available = data.available();
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
/*
|
||||
check if there is a firmware on the other OTA partition that you can bootinto
|
||||
*/
|
||||
bool canRollBack();
|
||||
/*
|
||||
set the other OTA partition as bootable (reboot to enable)
|
||||
*/
|
||||
bool rollBack();
|
||||
|
||||
private:
|
||||
void _reset();
|
||||
void _abort(uint8_t err);
|
||||
bool _writeBuffer();
|
||||
bool _verifyHeader(uint8_t data);
|
||||
bool _verifyEnd();
|
||||
|
||||
|
||||
uint8_t _error;
|
||||
uint8_t *_buffer;
|
||||
size_t _bufferLen;
|
||||
size_t _size;
|
||||
THandlerFunction_Progress _progress_callback;
|
||||
uint32_t _progress;
|
||||
uint32_t _command;
|
||||
const esp_partition_t* _partition;
|
||||
|
||||
String _target_md5;
|
||||
MD5Builder _md5;
|
||||
};
|
||||
|
||||
extern UpdateClass Update;
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
std::array<uint32_t, 1433> vendors = {
|
||||
std::array<uint32_t, 1552> vendors = {
|
||||
0x38f23e, 0x807abf, 0x90e7c4, 0x7c6193, 0x485073, 0x74e28c, 0x8463d6,
|
||||
0xd48f33, 0x2c8a72, 0x980d2e, 0xa826d9, 0xd4206d, 0x00155d, 0x806c1b,
|
||||
0xa470d6, 0x985fd3, 0x1c69a5, 0x382de8, 0xd087e2, 0x205531, 0x5440ad,
|
||||
@ -14,193 +14,210 @@ std::array<uint32_t, 1433> vendors = {
|
||||
0xd0dfc7, 0x1c62b8, 0x18e2c2, 0x001a8a, 0x002567, 0xa8f274, 0x001599,
|
||||
0x0012fb, 0x7cf854, 0x8cc8cd, 0xe81132, 0xa02195, 0x8c71f8, 0x04180f,
|
||||
0x9463d1, 0x0cdfa4, 0xcc051b, 0x68ebae, 0x60d0a9, 0x60a10a, 0xa07591,
|
||||
0x001fcc, 0xec107b, 0xa01081, 0xf4f524, 0x9c99a0, 0x185936, 0x98fae3,
|
||||
0x640980, 0x8cbebe, 0xf8a45f, 0xbc8385, 0x900628, 0xd4ae05, 0x3c0518,
|
||||
0xc40bcb, 0xe8bba8, 0xbc3aea, 0x8c0ee3, 0x6c5c14, 0x78abbb, 0x1816c9,
|
||||
0x001fcc, 0xec107b, 0xa01081, 0xf4f524, 0xbc8385, 0x900628, 0xd4ae05,
|
||||
0x3c0518, 0xe8bba8, 0xbc3aea, 0x8c0ee3, 0x6c5c14, 0x78abbb, 0x1816c9,
|
||||
0xfc8f90, 0x244b03, 0x988389, 0x14bb6e, 0x1c3ade, 0xf83f51, 0xd8e0e1,
|
||||
0xecf342, 0x5092b9, 0xb4bff6, 0xc8d7b0, 0x982d68, 0xecd09f, 0xe446da,
|
||||
0xf4f5db, 0xd80831, 0xdc5583, 0x2c54cf, 0x001fe3, 0x0026e2, 0x001e75,
|
||||
0x6cd68a, 0x2021a5, 0x0c4885, 0xdc0b34, 0xac0d1b, 0x60e3ac, 0xf895c7,
|
||||
0xc4438f, 0xa816b2, 0xe892a4, 0x700514, 0x88c9d0, 0x2c598a, 0x18f0e4,
|
||||
0xec8350, 0x4cdd31, 0x703eac, 0x6c94f8, 0x84788b, 0x2cf0ee, 0x68d93c,
|
||||
0x24e314, 0x28f076, 0x285aeb, 0x087402, 0xccc760, 0x705aac, 0xfc643a,
|
||||
0xd4e6b7, 0x2802d8, 0x9c2ea1, 0x68967b, 0xbc6778, 0xa82066, 0xb065bd,
|
||||
0xf0dce2, 0x7cd1c3, 0x705681, 0x2cbe08, 0x783a84, 0x84b153, 0x6476ba,
|
||||
0x54ae27, 0xf437b7, 0xf0d1a9, 0x34c059, 0x04f7e4, 0x10ddb1, 0xb4f0ab,
|
||||
0x848506, 0x7831c1, 0x8c7c92, 0xd0e140, 0xacfdec, 0xf82793, 0x40a6d9,
|
||||
0x109add, 0xf0b479, 0x58b035, 0x34159e, 0x286aba, 0xec852f, 0x44d884,
|
||||
0x003ee1, 0x7c11be, 0x04e536, 0x881fa1, 0x04db56, 0x9cfc01, 0xc81ee7,
|
||||
0x34363b, 0xc01ada, 0xacbc32, 0x70700d, 0x7c5049, 0x503237, 0xd4619d,
|
||||
0xb0481a, 0x989e63, 0xdca904, 0x48a195, 0x6cab31, 0x6c96cf, 0x3035ad,
|
||||
0xa8be27, 0xb8634d, 0x9ce33f, 0xf0989d, 0xace4b5, 0xe42b34, 0x1c36bb,
|
||||
0x3c2eff, 0xf0766f, 0x40cbc0, 0x4098ad, 0x6c4d73, 0xc48466, 0xd02b20,
|
||||
0x3010e4, 0x380f4a, 0x685b35, 0xc86f1d, 0x701124, 0x38484c, 0x041552,
|
||||
0x786c1c, 0xbc3baf, 0x00a040, 0x60fec5, 0xcc4463, 0x6c72e7, 0x18af61,
|
||||
0x00cdfe, 0xac61ea, 0x38b54d, 0x60c547, 0x28e02c, 0x50ead6, 0x4860bc,
|
||||
0x403004, 0x0c74c2, 0xa4b197, 0x7cf05f, 0xa4f1e8, 0x70a2b3, 0x4c57ca,
|
||||
0x68fb7e, 0x90c1c6, 0x9cf48e, 0xfcd848, 0x64b9e8, 0x001cb3, 0x000d93,
|
||||
0x30d9d9, 0x6030d4, 0x94bf2d, 0xc49880, 0xe0338e, 0x68fef7, 0xbce143,
|
||||
0x645aed, 0xc0b658, 0x881908, 0xfc2a9c, 0x48605f, 0x188796, 0x002376,
|
||||
0x84100d, 0x04c23e, 0x5c5188, 0xe89120, 0x9c6c15, 0x4886e8, 0x2c2997,
|
||||
0x102f6b, 0x00eebd, 0x281878, 0x6045bd, 0x7ced8d, 0xe85b5b, 0x000d3a,
|
||||
0xe09861, 0xf4f1e1, 0x60beb5, 0xb4e1c4, 0x70aab2, 0x0026ff, 0x406f2a,
|
||||
0x002557, 0xf05a09, 0x503275, 0x28cc01, 0xb46293, 0x04fe31, 0x845181,
|
||||
0xd831cf, 0xf8d0bd, 0xfcc734, 0xe4b021, 0xb0ec71, 0x3cbbfd, 0x2cae2b,
|
||||
0xc488e5, 0x7c9122, 0xe8b4c8, 0x18895b, 0xe0db10, 0xe09971, 0x6077e2,
|
||||
0x680571, 0x6c2f2c, 0x300d43, 0x6c2779, 0x607edd, 0x9c2a83, 0xe45d75,
|
||||
0xe4faed, 0xc83f26, 0x54f201, 0xa06090, 0xac3743, 0x141f78, 0x006f64,
|
||||
0xdc6672, 0x001e7d, 0x3c6200, 0x0024e9, 0x002399, 0xe4e0c5, 0xe8039a,
|
||||
0xc4731e, 0x8c7712, 0x2013e0, 0x0007ab, 0x0021d2, 0xbc4760, 0xd0176a,
|
||||
0x2cbaba, 0x24920e, 0x40d3ae, 0xf01dbc, 0x24dbed, 0xac3613, 0x1449e0,
|
||||
0xc0bdd1, 0xe8508b, 0xf025b7, 0xc8ba94, 0xec1f72, 0x9852b1, 0x1489fd,
|
||||
0xccfe3c, 0x789ed0, 0xe440e2, 0x1caf05, 0xe492fb, 0x0073e0, 0xbc4486,
|
||||
0x380b40, 0x002490, 0x0023d7, 0xfca13e, 0xa00798, 0x945103, 0xc819f7,
|
||||
0x2c4401, 0x28e31f, 0x0c1daf, 0x14f65a, 0x742344, 0xf0b429, 0xec51bc,
|
||||
0xf079e8, 0x887598, 0xd0b128, 0xd00401, 0xf06d78, 0x10683f, 0x74a722,
|
||||
0x58a2b5, 0x64899a, 0x88074b, 0x64bc0c, 0xa039f7, 0x041b6d, 0x001f6b,
|
||||
0x30b4b8, 0x503cea, 0x0c9838, 0x54fcf0, 0x08aed6, 0xa816d0, 0x88bd45,
|
||||
0x544e90, 0xd03311, 0x70e72c, 0xc0cecd, 0x98e0d9, 0xe0accb, 0x78d75f,
|
||||
0x2078f0, 0x985aeb, 0xa45e60, 0x006d52, 0x5cadcf, 0xb8e856, 0x90b21f,
|
||||
0xa8bbcf, 0xc8b5b7, 0x18af8f, 0xf4f951, 0xf0c1f1, 0xec3586, 0x88cb87,
|
||||
0xac3c0b, 0xcc785f, 0xe88d28, 0x3ce072, 0xf41ba1, 0xa85b78, 0x9cf387,
|
||||
0x34a395, 0x48437c, 0xac87a3, 0x00f76f, 0xc0f2fb, 0x1caba7, 0x60facd,
|
||||
0x680927, 0x78a3e4, 0x68a86d, 0xb817c2, 0xb88d12, 0x5c8d4e, 0xe06678,
|
||||
0x1c1ac0, 0xc8f650, 0x60d9c7, 0x44fb42, 0x64a3cb, 0xd8d1cb, 0x542696,
|
||||
0x14109f, 0xbc52b7, 0xe0c97a, 0x5c95ae, 0x8cfaba, 0x0cbc9f, 0xbc4cc4,
|
||||
0x0c1539, 0x908d6c, 0x80006e, 0xb418d1, 0x1499e2, 0xe0c767, 0xa860b6,
|
||||
0x24f094, 0x90b0ed, 0xc4b301, 0xe05f45, 0x483b38, 0x88e87f, 0xb853ac,
|
||||
0x2c3361, 0x784f43, 0x404d7f, 0xbc926b, 0x0452f3, 0x241eeb, 0xf431c3,
|
||||
0x64a5c3, 0x606944, 0xe498d6, 0x0cd746, 0x440010, 0x1c9e46, 0x7c04d0,
|
||||
0xbc9fef, 0x8866a5, 0x70f087, 0x886b6e, 0x4c74bf, 0x844167, 0xb4f61c,
|
||||
0xe49adc, 0xb8c111, 0x3408bc, 0xd0817a, 0xc4618b, 0x68ab1e, 0x2c61f6,
|
||||
0x0026bb, 0x00254b, 0x002436, 0x002332, 0x002312, 0x0019e3, 0x001451,
|
||||
0x000a27, 0x003065, 0x0050e4, 0xd023db, 0xe0b9ba, 0x3451c9, 0x8c5877,
|
||||
0x9803d8, 0xc82a14, 0x88c663, 0x8c7b9d, 0x5855ca, 0xcc08e0, 0xe80688,
|
||||
0xecf342, 0x5092b9, 0xb4bff6, 0xc8d7b0, 0x982d68, 0xd80831, 0xdc5583,
|
||||
0x2c54cf, 0x001fe3, 0x0026e2, 0x001e75, 0x6cd68a, 0x2021a5, 0x0c4885,
|
||||
0xdc0b34, 0xac0d1b, 0x60e3ac, 0xf895c7, 0xc4438f, 0xa816b2, 0xe892a4,
|
||||
0x700514, 0x88c9d0, 0x2c598a, 0xec8350, 0x4cdd31, 0x705aac, 0xfc643a,
|
||||
0xd4e6b7, 0x2802d8, 0x48605f, 0xf0766f, 0x40cbc0, 0x4098ad, 0x6c4d73,
|
||||
0xc48466, 0xb8634d, 0x503237, 0xd4619d, 0xb0481a, 0x989e63, 0xdca904,
|
||||
0x48a195, 0x6cab31, 0x7c5049, 0xe42b34, 0x1c36bb, 0x3c2eff, 0x6c96cf,
|
||||
0x3035ad, 0xa8be27, 0x70a2b3, 0x4c57ca, 0x68fb7e, 0x90c1c6, 0xa4f1e8,
|
||||
0xac61ea, 0x38b54d, 0x00cdfe, 0x18af61, 0xcc4463, 0x34159e, 0x58b035,
|
||||
0xf0b479, 0x109add, 0x40a6d9, 0x7cf05f, 0xa4b197, 0x0c74c2, 0x403004,
|
||||
0x4860bc, 0xd02b20, 0x9ce33f, 0xf0989d, 0xace4b5, 0x6c72e7, 0x60fec5,
|
||||
0x00a040, 0x000d93, 0xacbc32, 0x30d9d9, 0x6030d4, 0x94bf2d, 0xc49880,
|
||||
0xe0338e, 0x68fef7, 0xbce143, 0x645aed, 0xc0b658, 0x881908, 0xfc2a9c,
|
||||
0x44d884, 0xec852f, 0x286aba, 0x705681, 0x7cd1c3, 0xf0dce2, 0xb065bd,
|
||||
0xa82066, 0xbc6778, 0x68967b, 0x848506, 0x54ae27, 0x6476ba, 0x84b153,
|
||||
0x783a84, 0x2cbe08, 0x24e314, 0x68d93c, 0x2cf0ee, 0x84788b, 0x6c94f8,
|
||||
0x703eac, 0xb4f0ab, 0x10ddb1, 0x04f7e4, 0x34c059, 0xf0d1a9, 0xbc3baf,
|
||||
0x786c1c, 0x041552, 0x38484c, 0x701124, 0xc86f1d, 0x685b35, 0x380f4a,
|
||||
0x3010e4, 0x04db56, 0x881fa1, 0x04e536, 0xf82793, 0xacfdec, 0xd0e140,
|
||||
0x8c7c92, 0x7831c1, 0xf437b7, 0x50ead6, 0x28e02c, 0x60c547, 0x7c11be,
|
||||
0x003ee1, 0xc01ada, 0x34363b, 0xc81ee7, 0x9cfc01, 0xccc760, 0x087402,
|
||||
0x285aeb, 0x28f076, 0x70700d, 0x9cf48e, 0xfcd848, 0x001cb3, 0x64b9e8,
|
||||
0x108ee0, 0x68e7c2, 0x3c576c, 0x0ce0dc, 0x702ad5, 0x889f6f, 0x1c427d,
|
||||
0x5029f5, 0x4c569d, 0x14c213, 0x38539c, 0x58e6ba, 0xb831b5, 0x90633b,
|
||||
0x782327, 0xf8a45f, 0x8cbebe, 0x640980, 0x98fae3, 0x185936, 0x9c99a0,
|
||||
0xc40bcb, 0xecd09f, 0xf4f5db, 0xe446da, 0x18f0e4, 0x9c2ea1, 0x50a009,
|
||||
0x20a60c, 0xf8e94e, 0xf40616, 0xbcb863, 0x188796, 0x002376, 0x84100d,
|
||||
0x04c23e, 0x5c5188, 0xe89120, 0x9c6c15, 0x4886e8, 0x2c2997, 0x102f6b,
|
||||
0x00eebd, 0x281878, 0x6045bd, 0x7ced8d, 0xe85b5b, 0x000d3a, 0xe09861,
|
||||
0xf4f1e1, 0x60beb5, 0xb4e1c4, 0x70aab2, 0x0026ff, 0x406f2a, 0x002557,
|
||||
0xf05a09, 0x503275, 0x28cc01, 0xb46293, 0x04fe31, 0x845181, 0xd831cf,
|
||||
0xf8d0bd, 0xfcc734, 0xe4b021, 0xb0ec71, 0x3cbbfd, 0x2cae2b, 0xc488e5,
|
||||
0x7c9122, 0xe8b4c8, 0x18895b, 0xe0db10, 0xe09971, 0x6077e2, 0x680571,
|
||||
0x6c2f2c, 0x300d43, 0x6c2779, 0x607edd, 0x9c2a83, 0xe45d75, 0xe4faed,
|
||||
0xc83f26, 0x54f201, 0xa06090, 0xac3743, 0x141f78, 0x006f64, 0xdc6672,
|
||||
0x001e7d, 0x3c6200, 0x0024e9, 0x002399, 0xe4e0c5, 0xe8039a, 0xc4731e,
|
||||
0x8c7712, 0x2013e0, 0x0007ab, 0x0021d2, 0xbc4760, 0xd0176a, 0x2cbaba,
|
||||
0x24920e, 0x40d3ae, 0xf01dbc, 0x24dbed, 0xac3613, 0x1449e0, 0xc0bdd1,
|
||||
0xe8508b, 0xf025b7, 0xc8ba94, 0xec1f72, 0x9852b1, 0x1489fd, 0xccfe3c,
|
||||
0x789ed0, 0xe440e2, 0x1caf05, 0xe492fb, 0x0073e0, 0xbc4486, 0x380b40,
|
||||
0x002490, 0x0023d7, 0xfca13e, 0xa00798, 0x945103, 0xc819f7, 0x2c4401,
|
||||
0xec51bc, 0xf079e8, 0x887598, 0xd0b128, 0xd00401, 0xf06d78, 0x10683f,
|
||||
0x74a722, 0x58a2b5, 0x64899a, 0x88074b, 0x64bc0c, 0xa039f7, 0x041b6d,
|
||||
0x001f6b, 0x30b4b8, 0x503cea, 0x54fcf0, 0x08aed6, 0xa816d0, 0x88bd45,
|
||||
0x641cb0, 0x3cdcbc, 0xf47190, 0x587a6a, 0xe4c483, 0x8cf5a3, 0x14568e,
|
||||
0x8058f8, 0xf0d7aa, 0xc49ded, 0xb0aa36, 0x2c5bb8, 0x1c48ce, 0x24f5aa,
|
||||
0xf877b8, 0x682737, 0x5056bf, 0x9097f3, 0x58c5cb, 0xacafb9, 0x30074d,
|
||||
0x5c5181, 0x389af6, 0xe0aa96, 0x507705, 0x2c4053, 0x084acf, 0x1cddea,
|
||||
0x08152f, 0xd461da, 0xc8d083, 0x88e9fe, 0x88ae07, 0x5c0947, 0x38892c,
|
||||
0x40831d, 0x50bc96, 0x9ce65e, 0x90dd5d, 0x08f69c, 0x00092d, 0xf8db7f,
|
||||
0xe899c4, 0x24da9b, 0x1c56fe, 0xe4907e, 0x80c5e6, 0x800184, 0xf8cfc5,
|
||||
0xc808e9, 0x206274, 0x30d587, 0xc0eefb, 0x502e5c, 0x847a88, 0x0025ae,
|
||||
0x002538, 0x0022a1, 0x00125a, 0x9cd917, 0x9068c3, 0x408805, 0xf8f1b6,
|
||||
0x001ccc, 0x94ebcd, 0xa4e4b8, 0x389496, 0x0cb319, 0x08ee8b, 0xa89fba,
|
||||
0xfc1910, 0x083d88, 0x5c2e59, 0x646cb2, 0xf884f2, 0x14b484, 0x608f5c,
|
||||
0x4cbca5, 0x78595e, 0xb0d09c, 0x4ca56d, 0xa48431, 0xe4f8ef, 0x1432d1,
|
||||
0xe458e7, 0x8cbfa6, 0x7840e4, 0x9000db, 0x183a2d, 0x08373d, 0x50f520,
|
||||
0xa4ebd3, 0x28987b, 0xf40e22, 0x9c3aaf, 0x0821ef, 0xa0cbfd, 0x34145f,
|
||||
0x6c8fb5, 0xac5f3e, 0x509ea7, 0xdccf96, 0x6c2483, 0xc09727, 0xd85b2a,
|
||||
0xacc33a, 0x88797e, 0x00e091, 0x6cd032, 0xc041f6, 0x0017d5, 0x001247,
|
||||
0xe4121d, 0x684898, 0xf409d8, 0xb479a7, 0x002339, 0xd487d8, 0x184617,
|
||||
0x5001bb, 0x380a94, 0xd857ef, 0x1c66aa, 0x58c38b, 0x001ee2, 0x001c43,
|
||||
0x001d25, 0x3c5a37, 0x549b12, 0x3c8bfe, 0x00265d, 0xd4e8b2, 0x0808c2,
|
||||
0xb0c4e7, 0xd890e8, 0x34aa8b, 0x24c696, 0x181eb0, 0x20d390, 0x343111,
|
||||
0x34be00, 0x78521a, 0x7825ad, 0xf4d9fb, 0x0017c9, 0x00166b, 0x00166c,
|
||||
0xe47cf9, 0x002454, 0x20d5bf, 0x30cda7, 0xc87e75, 0x00233a, 0x60a4d0,
|
||||
0x2c0e3d, 0xd4970b, 0x64cc2e, 0xb0e235, 0x38a4ed, 0xf48b32, 0x7c787e,
|
||||
0xc0d3c0, 0x440444, 0xc09f05, 0xcc2d83, 0x38295a, 0x4c1a3d, 0xa81b5a,
|
||||
0xdc6dcd, 0x54fa3e, 0x0c8910, 0xfcf136, 0x981dfa, 0x84a466, 0x1867b0,
|
||||
0xccb11a, 0xb8bbaf, 0x60c5ad, 0x28395e, 0xc4ae12, 0xdc74a8, 0xc087eb,
|
||||
0x74f61c, 0x986f60, 0x4c189a, 0x3cf591, 0x602101, 0xa89675, 0x608e08,
|
||||
0x7c2edd, 0x3cf7a4, 0x342d0d, 0x94d029, 0x308454, 0x4c49e3, 0x087808,
|
||||
0xd03169, 0xbc5451, 0x00bf61, 0xf80cf3, 0x30766f, 0x8c3ae3, 0x78f882,
|
||||
0xb4f1da, 0x0021fb, 0xd013fd, 0xa8b86e, 0x04b167, 0xd86375, 0xdcbfe9,
|
||||
0x306a85, 0x2047da, 0x8035c1, 0xd02598, 0xa8667f, 0x7014a6, 0x10417f,
|
||||
0xac293a, 0x94e96a, 0x0c4de9, 0x907240, 0xa88808, 0xc8e0eb, 0x54e43a,
|
||||
0x28e14c, 0x848e0c, 0xb03495, 0xf0f61c, 0x0c3021, 0xd89695, 0x649abe,
|
||||
0x5cf5da, 0x20a2e4, 0xf02475, 0x24a074, 0x8863df, 0x609217, 0x34e2fd,
|
||||
0x0c3e9f, 0x6c709f, 0x6c4008, 0x5c97f3, 0x90fd61, 0x006171, 0x80e650,
|
||||
0xdc2b2a, 0xb844d9, 0xe0f5c6, 0x949426, 0xcc29f5, 0x58404e, 0xdc0c5c,
|
||||
0x2c200b, 0xdca4ca, 0x8c8fe9, 0x9810e8, 0xb49cdf, 0xa4e975, 0xc0a53e,
|
||||
0x9800c6, 0x787b8a, 0x3866f0, 0x20ee28, 0x08f4ab, 0x8c8590, 0xb48b19,
|
||||
0xe49a79, 0x28a02b, 0xb44bd2, 0x2cf0a2, 0xecadb8, 0x9801a7, 0x609ac1,
|
||||
0xf07960, 0x9c8ba0, 0x4c3275, 0xe4e4ab, 0xc8334b, 0x00f4b9, 0x0c771a,
|
||||
0x74e1b6, 0x64200c, 0xc0847a, 0x183451, 0xfc253f, 0x1040f3, 0x6cc26b,
|
||||
0x182032, 0x70dee2, 0x00c610, 0x101c0c, 0x7cfadf, 0x5cf938, 0x3871de,
|
||||
0xbc5436, 0x9c4fda, 0x1c5cf2, 0x60fb42, 0x002500, 0x00236c, 0x0021e9,
|
||||
0x001ff3, 0x001f5b, 0x001e52, 0x001d4f, 0x001124, 0xa8fad8, 0x5c969d,
|
||||
0xe48b7f, 0x84fcfe, 0x444c0c, 0x8c2daa, 0x6c3e6d, 0x189efc, 0xc09f42,
|
||||
0xb8f6b1, 0x406c8f, 0xa4d1d2, 0x040cce, 0xd89e3f, 0x28e7cf, 0xc8bcc8,
|
||||
0xd8a25e, 0x90840d, 0xf81edf, 0xb0ca68, 0x98ca33, 0x68ef43, 0xcc2db7,
|
||||
0xd4a33d, 0xe4e0a6, 0x70ef00, 0x80ad16, 0x641cae, 0x14205e, 0x5c1dd9,
|
||||
0x18f1d8, 0xf86fc1, 0xf099b6, 0xdcd3a2, 0x38e7d8, 0xd8b377, 0xb4cef6,
|
||||
0xd40b1a, 0x5882a8, 0xb4ae2b, 0x0c413e, 0xd0929e, 0x4480eb, 0xb84fd5,
|
||||
0xec59e7, 0x3059b7, 0x501ac5, 0x1cb094, 0xa0f450, 0x002248, 0xec8892,
|
||||
0xb07994, 0x141aa3, 0xccc3ea, 0x34bb26, 0x40786a, 0xf40b93, 0x68ed43,
|
||||
0x34bb1f, 0x489d24, 0x000f86, 0xacee9e, 0xc08997, 0x2827bf, 0xf05b7b,
|
||||
0x7cf90e, 0xac5a14, 0xb0c559, 0xbcd11f, 0xa0b4a5, 0x80656d, 0x48137e,
|
||||
0xe83a12, 0x9c0298, 0x6c8336, 0xb8c68e, 0x74458a, 0xa49a58, 0xb4ef39,
|
||||
0x14a364, 0x3ca10d, 0x206e9c, 0x183f47, 0x0c715d, 0x0c1420, 0xa80600,
|
||||
0x6cf373, 0x78c3e9, 0xc83870, 0x288335, 0x44783e, 0x202d07, 0x98398e,
|
||||
0x348a7b, 0xbc765e, 0x78009e, 0x68c44d, 0xf8e61a, 0x888322, 0x84b541,
|
||||
0x0015b9, 0x001df6, 0xece09b, 0x606bbd, 0x0000f0, 0x4844f7, 0x1c5a3e,
|
||||
0xf47b5e, 0x008701, 0xfc4203, 0x1c232c, 0xcc61e5, 0x404e36, 0x009ec8,
|
||||
0xacf7f3, 0x102ab3, 0x584498, 0xa086c6, 0x7c1dd9, 0x9893cc, 0x3ccd93,
|
||||
0xf06bca, 0x3423ba, 0xd022be, 0xd02544, 0xbc20a4, 0x14f42a, 0xbc851f,
|
||||
0xb85e7b, 0xc462ea, 0x0023d6, 0x002491, 0x001b98, 0x44f459, 0x34c3ac,
|
||||
0x94d771, 0x4c3c16, 0x9401c2, 0xb43a28, 0xd0c1b1, 0xf008f1, 0x78471d,
|
||||
0x3816d1, 0xd48890, 0x002566, 0x00265f, 0xacc1ee, 0x5cba37, 0x7802f8,
|
||||
0x3096fb, 0xf0ee10, 0xa43d78, 0xec01ee, 0xb83765, 0xc4576e, 0x90f1aa,
|
||||
0x78bdbc, 0xd47ae2, 0x84c0ef, 0x7c1c68, 0xd463c6, 0x508f4c, 0x7c6456,
|
||||
0x448f17, 0x04d6aa, 0x9ce063, 0xf06e0b, 0x5c865c, 0xf0b0e7, 0x209bcd,
|
||||
0xcc20e8, 0x04d13a, 0x0cf346, 0x003de8, 0x485929, 0x34fcef, 0x002483,
|
||||
0x001c62, 0x583f54, 0x40b0fa, 0xa8922c, 0x98d6f7, 0x505527, 0x0034da,
|
||||
0xa09169, 0x88365f, 0x9c8c6e, 0xbcffeb, 0x685acf, 0x48746e, 0x54724f,
|
||||
0x04f13e, 0x600308, 0x80ea96, 0x24a2e1, 0x90b931, 0x280b5c, 0xa8968a,
|
||||
0x9c04eb, 0x885395, 0x80929f, 0x98b8e3, 0xd8004d, 0x98fe94, 0x68644b,
|
||||
0xf099bf, 0xfce998, 0x48e9f1, 0x4c7c5f, 0x60f81d, 0x689c70, 0x2cb43a,
|
||||
0x042665, 0xf4f15a, 0x207d74, 0x4c8d79, 0xfcfc48, 0x38c986, 0x70ece4,
|
||||
0xd81d72, 0x94f6a3, 0x78fd94, 0x48d705, 0x7c6df8, 0x3cab8e, 0x787e61,
|
||||
0xd4f46f, 0xc88550, 0xac7f3e, 0xa4c361, 0x087045, 0x40331a, 0xdc3714,
|
||||
0x789f70, 0x64b0a6, 0x84fcac, 0x6c19c0, 0x20ab37, 0xc0d012, 0xd4dccd,
|
||||
0x484baa, 0xf80377, 0x14bd61, 0x78886d, 0xa85c2c, 0x00db70, 0xbcec5d,
|
||||
0xdc415f, 0x30636b, 0x0c5101, 0x086d41, 0x04d3cf, 0x203cae, 0x748d08,
|
||||
0xa03be3, 0x186590, 0x0010fa, 0x000502, 0xb8782e, 0xa4d18c, 0xcc25ef,
|
||||
0x68dbca, 0x044bed, 0x6c8dc1, 0x38cada, 0xf45c89, 0x581faa, 0x24ab81,
|
||||
0x70cd60, 0x7cc537, 0xc42c03, 0xd83062, 0x40d32d, 0x7c6d62, 0x286ab8,
|
||||
0x403cfc, 0xb8c75d, 0xe8040b, 0xe4ce8f, 0x3c0754, 0xa46706, 0x80b03d,
|
||||
0xc83c85, 0xa04ea7, 0x409c28, 0x08e689, 0x4cb199, 0x98d6bb, 0x3cd0f8,
|
||||
0x7cc3a1, 0x002608, 0x001ec2, 0x001b63, 0x0017f2, 0x0016cb, 0x000393,
|
||||
0x804971, 0x64e682, 0xb4f7a1, 0x785dc8, 0x48c796, 0x804e70, 0x3880df,
|
||||
0x1094bb, 0xf01898, 0x48a91c, 0xa056f3, 0x549963, 0x28ff3c, 0x902155,
|
||||
0x64a769, 0xbccfcc, 0xa4516f, 0x3c8375, 0x149a10, 0x0ce725, 0xc0335e,
|
||||
0x20a99b, 0x4c0bbe, 0x7c1e52, 0xdcb4c4, 0x001dd8, 0x0017fa, 0x0003ff,
|
||||
0xf8e079, 0x1430c6, 0xe0757d, 0x9cd35b, 0x60af6d, 0xb85a73, 0x103047,
|
||||
0x109266, 0xb047bf, 0x7c0bc6, 0x804e81, 0x244b81, 0x50a4c8, 0x8425db,
|
||||
0xd8c4e9, 0x50c8e5, 0x446d6c, 0x38d40b, 0x647791, 0x781fdb, 0x08fc88,
|
||||
0x30c7ae, 0x18227e, 0x00f46f, 0x9ce6e7, 0xe498d1, 0x5cca1a, 0x70288b,
|
||||
0x4849c7, 0x205ef7, 0x182666, 0xc06599, 0xcc07ab, 0xe84e84, 0x50fc9f,
|
||||
0xe432cb, 0x889b39, 0xbcb1f3, 0x38ece4, 0xccf9e8, 0xf0e77e, 0x5ce8eb,
|
||||
0xb8d9ce, 0x70f927, 0x301966, 0x28bab5, 0x103b59, 0x6cb7f4, 0x001ee1,
|
||||
0x0018af, 0xbc72b1, 0x78f7be, 0xf49f54, 0x00214c, 0x001632, 0xd0667b,
|
||||
0x001377, 0x50b7c3, 0x8018a7, 0x444e1a, 0xe8e5d6, 0x5492be, 0x101dc0,
|
||||
0x0021d1, 0x68dfdd, 0xc46ab7, 0xfc64ba, 0x2082c0, 0x3480b3, 0x7451ba,
|
||||
0x64b473, 0xcc2d8c, 0x949aa9, 0x20dbab, 0x5c9960, 0x948bc1, 0x4827ea,
|
||||
0x388c50, 0xa09347, 0xc8f230, 0x1c77f6, 0xe44790, 0xd4503f, 0x40163b,
|
||||
0x5c497d, 0xe47dbd, 0x503da1, 0x508569, 0x1077b1, 0x5cf6dc, 0x380195,
|
||||
0xbc1485, 0x88d50c, 0x947be7, 0x00ec0a, 0x54bd79, 0xdc44b6, 0x1007b6,
|
||||
0xc0174d, 0xa407b6, 0x149f3c, 0x88b4a6, 0x2c5491, 0x5c70a3, 0x10f96f,
|
||||
0xf01c13, 0x00aa70, 0xbcf5ac, 0xccfa00, 0xf8a9d0, 0x805a04, 0x5caf06,
|
||||
0xb81daa, 0x10f1f2, 0x0025e5, 0x0022a9, 0xc49a02, 0x344df7, 0xd41a3f,
|
||||
0xcc6ea4, 0xa46cf1, 0x0ca8a7, 0x54b802, 0x0469f8, 0xbc6c21, 0xc869cd,
|
||||
0x80d605, 0x587f57, 0xa4b805, 0x70480f, 0x18f643, 0x748114, 0x18ee69,
|
||||
0xf0dbe2, 0xb8098a, 0x549f13, 0x2c1f23, 0x507a55, 0x9c35eb, 0xa43135,
|
||||
0xd0034b, 0xa01828, 0xd0a637, 0xd04f7e, 0xd8bb2c, 0x80be05, 0xe0b52d,
|
||||
0x68ae20, 0xe8802e, 0x7c0191, 0x9c293f, 0x341298, 0x903c92, 0x24240e,
|
||||
0xa0999b, 0xe0f847, 0x442a60, 0x1093e9, 0xdc2b61, 0xb8ff61, 0x18e7f4,
|
||||
0x78ca39, 0x5c5948, 0x60334b, 0x9027e4, 0xd49a20, 0xb09fba, 0x8c006d,
|
||||
0xc06394, 0x843835, 0xe4c63d, 0x54eaa8, 0xa886dd, 0xaccf5c, 0xf0dbf8,
|
||||
0x98f0ab, 0xdc9b9c, 0x8c2937, 0xdc86d8, 0xa88e24, 0xd8cf9c, 0x04489a,
|
||||
0x3c15c2, 0x20c9d0, 0x74e2f5, 0x842999, 0x9c207b, 0x283737, 0x148fc6,
|
||||
0x28cfda, 0x145a05, 0xa0edcd, 0x1ce62b, 0x3090ab, 0x7073cb, 0xf0cba1,
|
||||
0x045453, 0x40b395, 0x008865, 0x30f7c5, 0x20768f, 0xc0ccf8, 0x80ed2c,
|
||||
0xe8b2ac, 0x8489ad, 0x8c8ef2, 0xf40f24, 0x84a134, 0x1c9148, 0x5cf7e6,
|
||||
0xa0d795, 0xcc088d, 0x00b362, 0xf86214, 0xb0702d, 0xd0c5f3, 0x60f445,
|
||||
0x5082d5, 0x9c84bf, 0x48bf6b, 0x245ba7, 0xbca920, 0xb019c6, 0x58e28f,
|
||||
0xac1f74, 0x080007, 0xe425e7, 0x28cfe9, 0x9060f1, 0x741bb2, 0x28ed6a,
|
||||
0x34ab37, 0x60a37d, 0x0056cd, 0x7081eb, 0x086698, 0x24f677, 0x7867d7,
|
||||
0x5433cb, 0xd0d2b0, 0xd88f76, 0x3c2ef9, 0xdc56e7, 0x347c25, 0xd4909c,
|
||||
0x041e64, 0x0026b0, 0x00264a, 0x0025bc, 0x0023df, 0x002241, 0x000a95,
|
||||
0x38e60a, 0x24181d, 0xf4c248, 0xa8515b, 0xc048e6, 0xd07714, 0x749eaf,
|
||||
0xb841a4, 0xf895ea, 0x50a67f, 0x647033, 0x846878};
|
||||
0x08152f, 0xb8c111, 0x3408bc, 0x844167, 0xb4f61c, 0x68ab1e, 0x2c61f6,
|
||||
0xe49adc, 0xd0817a, 0xc4618b, 0x3451c9, 0xe0b9ba, 0xd023db, 0xb88d12,
|
||||
0xb817c2, 0x68a86d, 0x78a3e4, 0x680927, 0x60facd, 0x1caba7, 0x784f43,
|
||||
0x404d7f, 0x7c04d0, 0xbc9fef, 0x8866a5, 0x88e87f, 0xb853ac, 0x2c3361,
|
||||
0xa860b6, 0x24f094, 0x90b0ed, 0xc4b301, 0xe05f45, 0x483b38, 0xe0c767,
|
||||
0x1c9e46, 0x0cd746, 0x440010, 0xe498d6, 0x606944, 0x0452f3, 0x241eeb,
|
||||
0xf431c3, 0x64a5c3, 0xbc926b, 0x0050e4, 0x003065, 0x000a27, 0x001451,
|
||||
0x8c7b9d, 0x88c663, 0xc82a14, 0x9803d8, 0x8c5877, 0x0019e3, 0x002312,
|
||||
0x002332, 0x002436, 0x00254b, 0x0026bb, 0x70f087, 0x886b6e, 0x4c74bf,
|
||||
0xe80688, 0xcc08e0, 0x5855ca, 0x5c0947, 0x38892c, 0x40831d, 0x50bc96,
|
||||
0x985aeb, 0x2078f0, 0x78d75f, 0xe0accb, 0x98e0d9, 0xc0cecd, 0x70e72c,
|
||||
0xd03311, 0x5cadcf, 0x006d52, 0x48437c, 0x34a395, 0x9cf387, 0xa85b78,
|
||||
0x908d6c, 0x0c1539, 0xbc4cc4, 0x0cbc9f, 0xa45e60, 0x544e90, 0x9ce65e,
|
||||
0x90dd5d, 0x08f69c, 0xd461da, 0xc8d083, 0x88e9fe, 0x88ae07, 0x18af8f,
|
||||
0xc8b5b7, 0xa8bbcf, 0x90b21f, 0xb8e856, 0x1499e2, 0xb418d1, 0x80006e,
|
||||
0x60d9c7, 0xc8f650, 0x1c1ac0, 0xe06678, 0x5c8d4e, 0xc0f2fb, 0x00f76f,
|
||||
0xac87a3, 0x542696, 0xd8d1cb, 0x64a3cb, 0x44fb42, 0xf41ba1, 0x3ce072,
|
||||
0xe88d28, 0xcc785f, 0xac3c0b, 0x88cb87, 0xec3586, 0xf0c1f1, 0xf4f951,
|
||||
0x8cfaba, 0x5c95ae, 0xe0c97a, 0xbc52b7, 0x14109f, 0x00c3f4, 0x74eb80,
|
||||
0xa82bb9, 0x7c6b9c, 0x1cc3eb, 0xbca58b, 0x70fd46, 0xd07fa0, 0x9caa1b,
|
||||
0x18d717, 0xb4cb57, 0x74b587, 0xd81c79, 0x8cfe57, 0xc0a600, 0xa823fe,
|
||||
0xfcaab6, 0xc0bdc8, 0xa887b3, 0x742344, 0xd832e3, 0xe06267, 0x482ca0,
|
||||
0x1801f1, 0x70bbe9, 0xf0b429, 0x0c9838, 0x0c1daf, 0x28e31f, 0x14f65a,
|
||||
0xd4c94b, 0x703a51, 0xdc080f, 0xf82d7c, 0x9c648b, 0x14d00d, 0x00092d,
|
||||
0xf8db7f, 0xe899c4, 0x24da9b, 0x1c56fe, 0xe4907e, 0x80c5e6, 0x800184,
|
||||
0xf8cfc5, 0xc808e9, 0x206274, 0x30d587, 0xc0eefb, 0x502e5c, 0x847a88,
|
||||
0x0025ae, 0x002538, 0x0022a1, 0x00125a, 0x9cd917, 0x9068c3, 0x408805,
|
||||
0xf8f1b6, 0x001ccc, 0x94ebcd, 0xa4e4b8, 0x389496, 0x0cb319, 0x08ee8b,
|
||||
0xa89fba, 0xfc1910, 0x083d88, 0x5c2e59, 0x646cb2, 0xf884f2, 0x14b484,
|
||||
0x608f5c, 0x4cbca5, 0x78595e, 0xb0d09c, 0x4ca56d, 0xa48431, 0xe4f8ef,
|
||||
0x1432d1, 0xe458e7, 0x8cbfa6, 0x7840e4, 0x9000db, 0x183a2d, 0x08373d,
|
||||
0x50f520, 0xa4ebd3, 0x28987b, 0xf40e22, 0x9c3aaf, 0x0821ef, 0xa0cbfd,
|
||||
0x34145f, 0x6c8fb5, 0xac5f3e, 0x509ea7, 0xdccf96, 0x6c2483, 0xc09727,
|
||||
0xd85b2a, 0xacc33a, 0x88797e, 0x00e091, 0x6cd032, 0xc041f6, 0x0017d5,
|
||||
0x001247, 0xe4121d, 0x684898, 0xf409d8, 0xb479a7, 0x002339, 0xd487d8,
|
||||
0x184617, 0x5001bb, 0x380a94, 0xd857ef, 0x1c66aa, 0x58c38b, 0x001ee2,
|
||||
0x001c43, 0x001d25, 0x3c5a37, 0x549b12, 0x3c8bfe, 0x00265d, 0xd4e8b2,
|
||||
0x0808c2, 0xb0c4e7, 0xd890e8, 0x34aa8b, 0x24c696, 0x181eb0, 0x20d390,
|
||||
0x343111, 0x34be00, 0x78521a, 0x7825ad, 0xf4d9fb, 0x0017c9, 0x00166b,
|
||||
0x00166c, 0xe47cf9, 0x002454, 0x20d5bf, 0x30cda7, 0xc87e75, 0x00233a,
|
||||
0x60a4d0, 0x2c0e3d, 0x7c787e, 0xc0d3c0, 0x440444, 0xc09f05, 0xcc2d83,
|
||||
0x38295a, 0x4c1a3d, 0xa81b5a, 0xdc6dcd, 0x54fa3e, 0x0c8910, 0xfcf136,
|
||||
0x981dfa, 0x84a466, 0x1867b0, 0xccb11a, 0xb8bbaf, 0x60c5ad, 0x28395e,
|
||||
0xc4ae12, 0xdc74a8, 0xc087eb, 0x74f61c, 0x986f60, 0x4c189a, 0x3cf591,
|
||||
0x602101, 0xa89675, 0x608e08, 0x7c2edd, 0x3cf7a4, 0x342d0d, 0x94d029,
|
||||
0x308454, 0x087808, 0xd03169, 0xbc5451, 0x641cae, 0xa4e975, 0xc0a53e,
|
||||
0x9800c6, 0x787b8a, 0x3866f0, 0x20ee28, 0x08f4ab, 0x8c8590, 0x68ef43,
|
||||
0xcc2db7, 0xd4a33d, 0xe4e0a6, 0x70ef00, 0xb0ca68, 0x9810e8, 0xb49cdf,
|
||||
0xdca4ca, 0x8c8fe9, 0x98ca33, 0xfc253f, 0x183451, 0xc0847a, 0x64200c,
|
||||
0x74e1b6, 0x0c771a, 0x00f4b9, 0xc8334b, 0xb8f6b1, 0xc09f42, 0x189efc,
|
||||
0x6c3e6d, 0x8c2daa, 0xe4e4ab, 0x58404e, 0xdc0c5c, 0x2c200b, 0x609ac1,
|
||||
0xf07960, 0x9c8ba0, 0x28a02b, 0xb44bd2, 0x9c4fda, 0x1c5cf2, 0x3871de,
|
||||
0xbc5436, 0x5cf938, 0x4c3275, 0x2cf0a2, 0xecadb8, 0x9801a7, 0xb48b19,
|
||||
0xe49a79, 0x406c8f, 0x00c610, 0x70dee2, 0x182032, 0x6cc26b, 0x1040f3,
|
||||
0x001d4f, 0x001e52, 0x001f5b, 0x001ff3, 0x0021e9, 0x00236c, 0x002500,
|
||||
0x60fb42, 0xf81edf, 0x90840d, 0xd8a25e, 0xc8bcc8, 0x28e7cf, 0xd89e3f,
|
||||
0x040cce, 0xa4d1d2, 0x7cfadf, 0x101c0c, 0x001124, 0x6c709f, 0x0c3e9f,
|
||||
0x34e2fd, 0x609217, 0x8863df, 0x80e650, 0x006171, 0x90fd61, 0x5c97f3,
|
||||
0x6c4008, 0x24a074, 0xf02475, 0x20a2e4, 0x5cf5da, 0x649abe, 0x94e96a,
|
||||
0xac293a, 0x10417f, 0xb844d9, 0xdc2b2a, 0x14205e, 0x5c1dd9, 0x18f1d8,
|
||||
0xf86fc1, 0xf099b6, 0x907240, 0x0c4de9, 0xd89695, 0x0c3021, 0xf0f61c,
|
||||
0xb03495, 0x848e0c, 0x949426, 0xe0f5c6, 0x28e14c, 0x54e43a, 0xc8e0eb,
|
||||
0xa88808, 0x444c0c, 0x84fcfe, 0xe48b7f, 0x5c969d, 0xa8fad8, 0x7014a6,
|
||||
0xa8667f, 0xd02598, 0xcc29f5, 0xdcd3a2, 0x08c5e1, 0x00bf61, 0xf80cf3,
|
||||
0x30766f, 0x8c3ae3, 0x78f882, 0xb4f1da, 0x0021fb, 0xd013fd, 0xa8b86e,
|
||||
0xdcbfe9, 0x306a85, 0x4466fc, 0xfca621, 0x0ccb85, 0xa4d990, 0xd003df,
|
||||
0x24fce5, 0xe4b2fb, 0xf83880, 0x241b7a, 0x402619, 0xbcfed9, 0x808223,
|
||||
0x3830f9, 0x6c006b, 0x38a4ed, 0xb0e235, 0x64cc2e, 0xd86375, 0x80ad16,
|
||||
0x2047da, 0x8035c1, 0x9487e0, 0x7c03ab, 0xd4970b, 0xf48b32, 0x4c49e3,
|
||||
0x04b167, 0xd8ce3a, 0xb8c74a, 0xfc183c, 0xc0e862, 0xec2ce2, 0x64c753,
|
||||
0x38e7d8, 0xd8b377, 0xb4cef6, 0xd40b1a, 0x5882a8, 0xb4ae2b, 0x0c413e,
|
||||
0xd0929e, 0x4480eb, 0xb84fd5, 0xec59e7, 0x3059b7, 0x501ac5, 0x1cb094,
|
||||
0xa0f450, 0x002248, 0xec8892, 0xb07994, 0x141aa3, 0xccc3ea, 0x34bb26,
|
||||
0x40786a, 0xf40b93, 0x68ed43, 0x34bb1f, 0x489d24, 0x000f86, 0xacee9e,
|
||||
0xc08997, 0x2827bf, 0xf05b7b, 0x7cf90e, 0xac5a14, 0xb0c559, 0xbcd11f,
|
||||
0xa0b4a5, 0x80656d, 0x48137e, 0xe83a12, 0x9c0298, 0x6c8336, 0xb8c68e,
|
||||
0x74458a, 0xa49a58, 0xb4ef39, 0x14a364, 0x3ca10d, 0x206e9c, 0x183f47,
|
||||
0x0c715d, 0x0c1420, 0xa80600, 0x6cf373, 0x78c3e9, 0xc83870, 0x288335,
|
||||
0x44783e, 0x202d07, 0x98398e, 0x348a7b, 0xbc765e, 0x78009e, 0x68c44d,
|
||||
0xf8e61a, 0x888322, 0x84b541, 0x0015b9, 0x001df6, 0xece09b, 0x606bbd,
|
||||
0x0000f0, 0x4844f7, 0x1c5a3e, 0xf47b5e, 0x008701, 0xfc4203, 0x1c232c,
|
||||
0xcc61e5, 0x404e36, 0x9893cc, 0x3ccd93, 0xf06bca, 0x3423ba, 0xd022be,
|
||||
0xd02544, 0xbc20a4, 0x14f42a, 0xbc851f, 0xb85e7b, 0xc462ea, 0x0023d6,
|
||||
0x002491, 0x001b98, 0x44f459, 0x34c3ac, 0x94d771, 0x4c3c16, 0x9401c2,
|
||||
0xb43a28, 0xd0c1b1, 0xf008f1, 0x78471d, 0x3816d1, 0xd48890, 0x002566,
|
||||
0x00265f, 0x5cba37, 0x3096fb, 0xf0ee10, 0xa43d78, 0xec01ee, 0xb83765,
|
||||
0xc4576e, 0x90f1aa, 0x78bdbc, 0xd47ae2, 0x84c0ef, 0x7c1c68, 0xd463c6,
|
||||
0x7c6456, 0x448f17, 0x04d6aa, 0x9ce063, 0xf06e0b, 0x5c865c, 0x003de8,
|
||||
0x08e689, 0x7836cc, 0x08d46a, 0x485929, 0x34fcef, 0x002483, 0x001c62,
|
||||
0x583f54, 0x40b0fa, 0xa8922c, 0x98d6f7, 0x505527, 0x0034da, 0xa09169,
|
||||
0x88365f, 0x9c8c6e, 0xbcffeb, 0x685acf, 0xb4f7a1, 0x785dc8, 0x48c796,
|
||||
0x804e70, 0x3880df, 0xdc415f, 0x30636b, 0xf45c89, 0x68dbca, 0x044bed,
|
||||
0x6c8dc1, 0x38cada, 0xa4d18c, 0x186590, 0x64b0a6, 0x84fcac, 0x6c19c0,
|
||||
0x20ab37, 0x203cae, 0x748d08, 0xa03be3, 0x7c6d62, 0x40d32d, 0xd83062,
|
||||
0xc42c03, 0x7cc537, 0x70cd60, 0xc0d012, 0xd4dccd, 0x484baa, 0xf80377,
|
||||
0x14bd61, 0xcc25ef, 0xb8782e, 0x000502, 0x0010fa, 0x000393, 0x0016cb,
|
||||
0x409c28, 0x78886d, 0xa85c2c, 0x00db70, 0x0c5101, 0x086d41, 0x04d3cf,
|
||||
0xbcec5d, 0x80b03d, 0xc83c85, 0xa04ea7, 0x0017f2, 0x001b63, 0x001ec2,
|
||||
0x002608, 0xa4c361, 0xac7f3e, 0x280b5c, 0x90b931, 0x24a2e1, 0x80ea96,
|
||||
0x600308, 0x04f13e, 0x54724f, 0x48746e, 0xd4f46f, 0x787e61, 0x60f81d,
|
||||
0x4c7c5f, 0x48e9f1, 0xfce998, 0xf099bf, 0x68644b, 0x789f70, 0x24ab81,
|
||||
0x581faa, 0xa46706, 0x3c0754, 0xe4ce8f, 0xe8040b, 0xb8c75d, 0x403cfc,
|
||||
0x98fe94, 0xd8004d, 0x98b8e3, 0x80929f, 0x885395, 0x9c04eb, 0xa8968a,
|
||||
0xdc3714, 0x40331a, 0x94f6a3, 0xd81d72, 0x70ece4, 0x38c986, 0xfcfc48,
|
||||
0x4c8d79, 0x207d74, 0xf4f15a, 0x042665, 0x2cb43a, 0x689c70, 0x087045,
|
||||
0x3cab8e, 0x7c6df8, 0x48d705, 0x78fd94, 0xc88550, 0x286ab8, 0x7cc3a1,
|
||||
0x3cd0f8, 0x98d6bb, 0x4cb199, 0x64e682, 0x804971, 0xcc20e8, 0x209bcd,
|
||||
0xf0b0e7, 0xa056f3, 0x549963, 0x28ff3c, 0x1094bb, 0xf01898, 0x48a91c,
|
||||
0x58b10f, 0x304b07, 0x1496e5, 0x80ceb9, 0xcc2119, 0x0057c1, 0x14c697,
|
||||
0xfc039f, 0x9c0cdf, 0x007204, 0x90e17b, 0x18810e, 0x608c4a, 0xa4d931,
|
||||
0x6cc7ec, 0x647bce, 0x584498, 0xacc1ee, 0x7802f8, 0x508f4c, 0x04d13a,
|
||||
0x0cf346, 0x082525, 0xf460e2, 0xa45046, 0x009ec8, 0x7c1dd9, 0xa086c6,
|
||||
0x102ab3, 0xacf7f3, 0x601d91, 0x38f9d3, 0x44e66e, 0xe83617, 0x344262,
|
||||
0xc09ad0, 0x902155, 0x64a769, 0xbccfcc, 0xa4516f, 0x3c8375, 0x149a10,
|
||||
0x0ce725, 0xc0335e, 0x20a99b, 0x4c0bbe, 0x7c1e52, 0xdcb4c4, 0x7c6f06,
|
||||
0x001dd8, 0x0017fa, 0x000a75, 0x0003ff, 0xf8e079, 0x1430c6, 0xe0757d,
|
||||
0x9cd35b, 0x60af6d, 0xb85a73, 0x103047, 0x109266, 0xb047bf, 0x7c0bc6,
|
||||
0x804e81, 0x244b81, 0x50a4c8, 0x8425db, 0xd8c4e9, 0x50c8e5, 0x446d6c,
|
||||
0x38d40b, 0x647791, 0x781fdb, 0x08fc88, 0x30c7ae, 0x18227e, 0x00f46f,
|
||||
0x9ce6e7, 0xe498d1, 0x5cca1a, 0x70288b, 0x4849c7, 0x205ef7, 0x182666,
|
||||
0xc06599, 0xcc07ab, 0xe84e84, 0x50fc9f, 0xe432cb, 0x889b39, 0xbcb1f3,
|
||||
0x38ece4, 0xccf9e8, 0xf0e77e, 0x5ce8eb, 0xb8d9ce, 0x70f927, 0x301966,
|
||||
0x28bab5, 0x103b59, 0x6cb7f4, 0x001ee1, 0x0018af, 0xbc72b1, 0x78f7be,
|
||||
0xf49f54, 0x00214c, 0x001632, 0xd0667b, 0x001377, 0x50b7c3, 0x8018a7,
|
||||
0x444e1a, 0xe8e5d6, 0x5492be, 0x101dc0, 0x0021d1, 0xcc2d8c, 0x949aa9,
|
||||
0x20dbab, 0x5c9960, 0x88b4a6, 0x2c5491, 0x5c70a3, 0x10f96f, 0xf01c13,
|
||||
0x00aa70, 0xbcf5ac, 0xccfa00, 0xf8a9d0, 0x805a04, 0x5caf06, 0xb81daa,
|
||||
0x10f1f2, 0x0025e5, 0x0022a9, 0xc49a02, 0x344df7, 0xd41a3f, 0xcc6ea4,
|
||||
0xa46cf1, 0x0ca8a7, 0x54b802, 0x24181d, 0xf4c248, 0xa8515b, 0xc048e6,
|
||||
0xd07714, 0x2816a8, 0x84a134, 0x1c9148, 0xc0ccf8, 0x80ed2c, 0xe8b2ac,
|
||||
0x8489ad, 0x20768f, 0x28ed6a, 0x34ab37, 0x60a37d, 0x0056cd, 0xbca920,
|
||||
0x5082d5, 0x9c84bf, 0x00b362, 0xf86214, 0xb0702d, 0xd0c5f3, 0x0023df,
|
||||
0x0025bc, 0x00264a, 0x0026b0, 0x041e64, 0xd49a20, 0x9027e4, 0x60334b,
|
||||
0x5c5948, 0x60f445, 0x5cf7e6, 0xa0d795, 0xcc088d, 0x8c8ef2, 0xf40f24,
|
||||
0x24f677, 0x7867d7, 0x5433cb, 0xd0d2b0, 0xd88f76, 0x3c2ef9, 0x7081eb,
|
||||
0x086698, 0x9060f1, 0x741bb2, 0x28cfe9, 0xe425e7, 0xb019c6, 0x58e28f,
|
||||
0xac1f74, 0x48bf6b, 0x245ba7, 0xdc56e7, 0x347c25, 0xd4909c, 0x080007,
|
||||
0x000a95, 0x002241, 0x18ee69, 0x748114, 0x18f643, 0xd0a637, 0xa01828,
|
||||
0xd0034b, 0xa43135, 0x9c35eb, 0x507a55, 0xa0999b, 0x24240e, 0x903c92,
|
||||
0xa88e24, 0xe8802e, 0x68ae20, 0xe0b52d, 0x80be05, 0xd8bb2c, 0xd04f7e,
|
||||
0x2c1f23, 0x549f13, 0xb8098a, 0xf0dbe2, 0x8c2937, 0xdc9b9c, 0x98f0ab,
|
||||
0xf0dbf8, 0xaccf5c, 0x3c15c2, 0x04489a, 0xd8cf9c, 0xa886dd, 0x54eaa8,
|
||||
0xe4c63d, 0x843835, 0xc06394, 0x8c006d, 0xb09fba, 0xdc86d8, 0x78ca39,
|
||||
0x18e7f4, 0xb8ff61, 0xdc2b61, 0x1093e9, 0x442a60, 0xe0f847, 0x145a05,
|
||||
0x28cfda, 0x148fc6, 0x283737, 0x045453, 0xf0cba1, 0x30f7c5, 0x008865,
|
||||
0x40b395, 0x3090ab, 0x1ce62b, 0xa0edcd, 0x842999, 0x74e2f5, 0x20c9d0,
|
||||
0x7073cb, 0x9c207b, 0x341298, 0x9c293f, 0x7c0191, 0x70480f, 0xa4b805,
|
||||
0x587f57, 0x80d605, 0xc869cd, 0xbc6c21, 0x0469f8, 0x749eaf, 0xb841a4,
|
||||
0xf895ea, 0x50a67f, 0x647033, 0x846878, 0x948bc1, 0x4827ea, 0x388c50,
|
||||
0xa09347, 0xc8f230, 0x1c77f6, 0xe44790, 0xd4503f, 0x40163b, 0x5c497d,
|
||||
0xe47dbd, 0x503da1, 0x508569, 0x1077b1, 0x5cf6dc, 0x380195, 0xbc1485,
|
||||
0x88d50c, 0x947be7, 0x54bd79, 0xdc44b6, 0x1007b6, 0xc0174d, 0xa407b6,
|
||||
0x149f3c, 0xd868c3, 0xc493d9, 0x00b5d0, 0x8c83e1, 0xfcb6d8, 0x6ce85c,
|
||||
0x007c2d, 0xf47def, 0x7c8bb5, 0xdcf756, 0x68dfdd, 0x64b473, 0x7451ba,
|
||||
0x3480b3, 0x2082c0, 0xfc64ba, 0xc46ab7, 0x00ec0a, 0x38e60a, 0x04e598,
|
||||
0x2ca9f0, 0x586b14, 0x94b01f, 0x94f6d6, 0x40bc60};
|
||||
|
@ -6,7 +6,7 @@
|
||||
static const char TAG[] = "wifi";
|
||||
|
||||
static wifi_country_t wifi_country = {WIFI_MY_COUNTRY, WIFI_CHANNEL_MIN,
|
||||
WIFI_CHANNEL_MAX, 0,
|
||||
WIFI_CHANNEL_MAX, 100,
|
||||
WIFI_COUNTRY_POLICY_MANUAL};
|
||||
|
||||
// using IRAM_:ATTR here to speed up callback function
|
||||
@ -27,15 +27,19 @@ IRAM_ATTR void wifi_sniffer_packet_handler(void *buff,
|
||||
|
||||
void wifi_sniffer_init(void) {
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
cfg.nvs_enable = 0; // we don't need any wifi settings from NVRAM
|
||||
cfg.nvs_enable = 0; // we don't need any wifi settings from NVRAM
|
||||
cfg.wifi_task_core_id = 0; // we want wifi task running on core 0
|
||||
wifi_promiscuous_filter_t filter = {
|
||||
.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // configure Wifi with cfg
|
||||
// .filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // only MGMT frames
|
||||
.filter_mask = WIFI_PROMIS_FILTER_MASK_ALL}; // we use all frames
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // configure Wifi with cfg
|
||||
ESP_ERROR_CHECK(
|
||||
esp_wifi_set_country(&wifi_country)); // set locales for RF and channels
|
||||
ESP_ERROR_CHECK(
|
||||
esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
|
||||
ESP_ERROR_CHECK(esp_wifi_stop());
|
||||
ESP_ERROR_CHECK(
|
||||
esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
|
||||
@ -43,30 +47,13 @@ void wifi_sniffer_init(void) {
|
||||
}
|
||||
|
||||
// Wifi channel rotation task
|
||||
void wifi_channel_loop(void *pvParameters) {
|
||||
|
||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||
|
||||
void switchWifiChannel(void *parameter) {
|
||||
while (1) {
|
||||
|
||||
if (ChannelTimerIRQ) {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
ChannelTimerIRQ = 0;
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
// rotates variable channel 1..WIFI_CHANNEL_MAX
|
||||
channel = (channel % WIFI_CHANNEL_MAX) + 1;
|
||||
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
|
||||
ESP_LOGD(TAG, "Wifi set channel %d", channel);
|
||||
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||
}
|
||||
|
||||
} // end of infinite wifi channel rotation loop
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // waiting for channel switch timer
|
||||
channel =
|
||||
(channel % WIFI_CHANNEL_MAX) + 1; // rotate channel 1..WIFI_CHANNEL_MAX
|
||||
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
|
||||
ESP_LOGD(TAG, "Wifi set channel %d", channel);
|
||||
}
|
||||
vTaskDelete(NULL); // shoud never be reached
|
||||
}
|
||||
|
||||
// IRQ handler
|
||||
void IRAM_ATTR ChannelSwitchIRQ() {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
ChannelTimerIRQ++;
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
}
|
@ -26,8 +26,7 @@ typedef struct {
|
||||
} wifi_ieee80211_packet_t;
|
||||
|
||||
void wifi_sniffer_init(void);
|
||||
void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
||||
void ChannelSwitchIRQ(void);
|
||||
void wifi_channel_loop(void *pvParameters);
|
||||
void IRAM_ATTR wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
||||
void switchWifiChannel(void * parameter);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user