Merge branch 'master' of https://github.com/cyberman54/ESP32-Paxcounter
This commit is contained in:
commit
c6fb9734cf
108
.clang-format
Normal file
108
.clang-format
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: false
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
|
|
224
README.md
224
README.md
@ -1,7 +1,7 @@
|
|||||||
# ESP32-Paxcounter
|
# ESP32-Paxcounter
|
||||||
**Wifi & Bluetooth driven, LoRaWAN enabled, battery powered mini Paxcounter built on cheap ESP32 boards**
|
**Wifi & Bluetooth driven, LoRaWAN enabled, battery powered mini Paxcounter built on cheap ESP32 LoRa IoT boards**
|
||||||
|
|
||||||
---> check branch "development" for latest alpha version <---
|
--> see development branch of this repository for latest alpha version <--
|
||||||
|
|
||||||
<img src="img/Paxcounter-title.jpg">
|
<img src="img/Paxcounter-title.jpg">
|
||||||
|
|
||||||
@ -19,16 +19,24 @@ This can all be done with a single small and cheap ESP32 board for less than $20
|
|||||||
|
|
||||||
# Hardware
|
# Hardware
|
||||||
|
|
||||||
Currently supported IoT boards:
|
Supported ESP32 based LoRa IoT boards:
|
||||||
- Heltec LoRa-32 {1}
|
- **Heltec LoRa-32** *a)*
|
||||||
- TTGOv1 {1}
|
- **TTGOv1** *a)*
|
||||||
- TTGOv2 {1}{4}
|
- **TTGOv2** *a,d)*
|
||||||
- Pycom LoPy {2}
|
- **TTGOv2.1** *a),e)*
|
||||||
- Pycom LoPy4 {2}
|
- **TTGO T-Beam** *d),e),f)*
|
||||||
- LoLin32 with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) {2}{3}
|
- **Pycom LoPy** *b),f)*
|
||||||
- LoLin32 Lite with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) {2}{3}
|
- **Pycom LoPy4** *b),f)*
|
||||||
|
- **Pycom FiPy** *b),f)*
|
||||||
|
- **LoLin32** with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) *b),c)*
|
||||||
|
- **LoLin32 Lite** with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) *b),c)*
|
||||||
|
|
||||||
{1} on board OLED Display supported; {2} on board RGB LED supported; {3} on board Hardware unique DEVEUI supported; {4} special wiring needed, see instructions in /hal/ttgov2.h
|
a) on board OLED Display supported;
|
||||||
|
b) on board RGB LED supported;
|
||||||
|
c) on board Hardware unique DEVEUI supported;
|
||||||
|
d) external wiring needed, see instructions in board.h file;
|
||||||
|
e) battery voltage monitoring supported;
|
||||||
|
f) on board GPS supported (for Pycom PyTrack expansion needed)
|
||||||
|
|
||||||
Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).<br>
|
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.<br>
|
||||||
@ -36,17 +44,7 @@ Hardware dependent settings (pinout etc.) are stored in board files in /hal dire
|
|||||||
<b>3D printable cases</b> can be found (and, if wanted so, ordered) on Thingiverse, see
|
<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> and <A HREF="https://www.thingiverse.com/thing:2811127">TTGOv2</A>, for example.<br>
|
<A HREF="https://www.thingiverse.com/thing:2670713">Heltec</A> and <A HREF="https://www.thingiverse.com/thing:2811127">TTGOv2</A>, for example.<br>
|
||||||
|
|
||||||
<b>Power consumption</b>:
|
<b>Power consumption</b> was metered at around 1000mW, depending on board (i.e. has display or not) and user settings in paxcounter.conf. If you are limited on battery, you may want to save around 30% power by disabling bluetooth (commenting out line *#define BLECOUNTER* in paxcounter.conf).
|
||||||
|
|
||||||
- Heltec ~720mW
|
|
||||||
- TTGOv1 TBD
|
|
||||||
- TTGOv2 ~990mW
|
|
||||||
- LoPy with expansion board: ~690mW
|
|
||||||
- LoPy pure, without expansion board: TBD
|
|
||||||
- LoLin32 with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora): TBD
|
|
||||||
- LoLin32 Lite with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora): TBD
|
|
||||||
|
|
||||||
These results where metered with software version 1.2.97 while continuously scanning wifi and ble, no LoRa TX’ing, OLED display (if present) on, 5V USB powered.
|
|
||||||
|
|
||||||
# Preparing
|
# Preparing
|
||||||
|
|
||||||
@ -64,14 +62,14 @@ If your device has silicon **Unique ID** which is stored in serial EEPROM Microc
|
|||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
|
||||||
Use <A HREF="https://platformio.org/">PlatformIO</A> with your preferred IDE for development and building this code.
|
Use <A HREF="https://platformio.org/">PlatformIO</A> with your preferred IDE for development and building this code. Make sure you have latest PlatformIO version.
|
||||||
|
|
||||||
# Uploading
|
# 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>
|
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>
|
||||||
The LoPy/LoPy4 board needs to be set manually. See these
|
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>
|
<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. If you later want to go back to the Pycom firmware, download the firmware from Pycom and flash it over.
|
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.
|
||||||
|
|
||||||
# Legal note
|
# Legal note
|
||||||
|
|
||||||
@ -81,7 +79,7 @@ The original Pycom firmware is not needed, so there is no need to update it befo
|
|||||||
|
|
||||||
(e.g. UK citizens may want to check [Data Protection Act 1998](https://ico.org.uk/media/1560691/wi-fi-location-analytics-guidance.pdf) and [GDPR 2018](https://ico.org.uk/for-organisations/guide-to-the-general-data-protection-regulation-gdpr/key-definitions/))
|
(e.g. UK citizens may want to check [Data Protection Act 1998](https://ico.org.uk/media/1560691/wi-fi-location-analytics-guidance.pdf) and [GDPR 2018](https://ico.org.uk/for-organisations/guide-to-the-general-data-protection-regulation-gdpr/key-definitions/))
|
||||||
|
|
||||||
(e.g. Citizens in the the Netherlands may want to read [this article](https://www.ivir.nl/publicaties/download/PrivacyInformatie_2016_6.pdf))
|
(e.g. Citizens in the the Netherlands may want to read [this article](https://www.ivir.nl/publicaties/download/PrivacyInformatie_2016_6.pdf) and [this article](https://autoriteitpersoonsgegevens.nl/nl/nieuws/europese-privacytoezichthouders-publiceren-opinie-eprivacyverordening))
|
||||||
|
|
||||||
Note: If you use this software you do this at your own risk. That means that you alone - not the authors of this software - are responsible for the legal compliance of an application using this or build from this software and/or usage of a device created using this software. You should take special care and get prior legal advice if you plan metering passengers in public areas and/or publish data drawn from doing so.
|
Note: If you use this software you do this at your own risk. That means that you alone - not the authors of this software - are responsible for the legal compliance of an application using this or build from this software and/or usage of a device created using this software. You should take special care and get prior legal advice if you plan metering passengers in public areas and/or publish data drawn from doing so.
|
||||||
|
|
||||||
@ -89,20 +87,92 @@ Note: If you use this software you do this at your own risk. That means that you
|
|||||||
|
|
||||||
Paxcounter generates identifiers for sniffed MAC adresses and collects them temporary in the device's RAM for a configurable scan cycle time (default 240 seconds). After each scan cycle the collected identifiers are cleared. Identifiers are generated by salting and hashing MAC adresses. The random salt value changes after each scan cycle. Identifiers and MAC adresses are never transferred to the LoRaWAN network. No persistent storing of MAC adresses, identifiers or timestamps and no other kind of analytics than counting are implemented in this code. Wireless networks are not touched by this code, but MAC adresses from wireless devices as well within as not within wireless networks, regardless if encrypted or unencrypted, are sniffed and processed by this code. If the bluetooth option in the code is enabled, bluetooth MACs are scanned and processed by the included BLE stack, then hashed and counted by this code.
|
Paxcounter generates identifiers for sniffed MAC adresses and collects them temporary in the device's RAM for a configurable scan cycle time (default 240 seconds). After each scan cycle the collected identifiers are cleared. Identifiers are generated by salting and hashing MAC adresses. The random salt value changes after each scan cycle. Identifiers and MAC adresses are never transferred to the LoRaWAN network. No persistent storing of MAC adresses, identifiers or timestamps and no other kind of analytics than counting are implemented in this code. Wireless networks are not touched by this code, but MAC adresses from wireless devices as well within as not within wireless networks, regardless if encrypted or unencrypted, are sniffed and processed by this code. If the bluetooth option in the code is enabled, bluetooth MACs are scanned and processed by the included BLE stack, then hashed and counted by this code.
|
||||||
|
|
||||||
# Payload format description
|
# LED
|
||||||
|
|
||||||
FPort1:
|
Legend for mono color on board LED:
|
||||||
|
|
||||||
byte 1: 16-bit WiFi counter, MSB
|
- Single Flash (50ms): seen a new Wifi or BLE device
|
||||||
byte 2: 16-bit WiFi counter, LSB
|
- Quick blink (20ms on each 1/5 second): joining LoRaWAN network in progress or pending
|
||||||
byte 3: 16-bit BLE counter, MSB
|
- Small blink (10ms on each 1/2 second): LoRaWAN data transmit in progress or pending
|
||||||
byte 4: 16-bit BLE counter, LSB
|
- Long blink (200ms on each 2 seconds): LoRaWAN stack error
|
||||||
|
|
||||||
FPort2:
|
Legend for RGB LED (LoPy/LoPy4/FiPy/Lolin32 only):
|
||||||
|
|
||||||
see remote command set
|
- Green each blink: seen a new Wifi device
|
||||||
|
- Magenta each blink: seen a new BLE device
|
||||||
|
- Yellow quick blink: joining LoRaWAN network in progress or pending
|
||||||
|
- Blue blink: LoRaWAN data transmit in progress or pending
|
||||||
|
- Red long blink: LoRaWAN stack error
|
||||||
|
|
||||||
# Remote command set
|
# Payload
|
||||||
|
|
||||||
|
**LoRaWAN Port #1:**
|
||||||
|
|
||||||
|
Paxcounter data
|
||||||
|
|
||||||
|
byte 1-2: Number of unique pax, first seen on Wifi
|
||||||
|
byte 3-4: Number of unique pax, first seen on Bluetooth [0 if BT disabled]
|
||||||
|
|
||||||
|
GPS data (only, if GPS is present and has a fix)
|
||||||
|
|
||||||
|
bytes 5-8: GPS latitude
|
||||||
|
bytes 9-12: GPS longitude
|
||||||
|
bytes 13-14: GPS number of satellites
|
||||||
|
bytes 15-16: GPS HDOP
|
||||||
|
bytes 17-18: GPS altitude [meter]
|
||||||
|
|
||||||
|
**LoRaWAN Port #2:**
|
||||||
|
|
||||||
|
- see remote control -
|
||||||
|
|
||||||
|
If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) (TTN) you may want to use a payload converter. Go to TTN Console - Application - Payload Formats and paste the code example below in tabs Decoder and Converter. Make sure that your application parses the fields `pax`, `ble` and `wifi`.
|
||||||
|
|
||||||
|
To map a GPS capable paxcounter device and at the same time contribute to TTN coverage mapping, you simply activate the [TTNmapper integration](https://www.thethingsnetwork.org/docs/applications/ttnmapper/) in TTN Console. Paxcounter generates ttnmapper compatible data fields.
|
||||||
|
|
||||||
|
**Decoder:**
|
||||||
|
|
||||||
|
```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++]) | (bytes[i++] << 8) | (bytes[i++] << 16) | bytes[i++] << 24 );
|
||||||
|
decoded.longitude = ( (bytes[i++]) | (bytes[i++] << 8) | (bytes[i++] << 16) | bytes[i++] << 24 );
|
||||||
|
decoded.sats = ( bytes[i++] | (bytes[i++] << 8) );
|
||||||
|
decoded.hdop = ( bytes[i++] | (bytes[i++] << 8) );
|
||||||
|
decoded.altitude = ( bytes[i++] | (bytes[i++] << 8) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Converter:**
|
||||||
|
|
||||||
|
```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.
|
The device listenes for remote control commands on LoRaWAN Port 2.
|
||||||
Each command is followed by exactly one parameter.
|
Each command is followed by exactly one parameter.
|
||||||
@ -121,10 +191,10 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
|||||||
1 = cumulative counter, mac counter is never reset
|
1 = cumulative counter, mac counter is never reset
|
||||||
2 = cyclic confirmed, like 0 but data is resent until confirmation by network received
|
2 = cyclic confirmed, like 0 but data is resent until confirmation by network received
|
||||||
|
|
||||||
0x03 (NOT YET IMPLEMENTED) set screen saver mode
|
0x03 set GPS data on/off
|
||||||
|
|
||||||
0 = screen saver off [default]
|
0 = GPS data off
|
||||||
1 = screen saver on
|
1 = GPS data on, appends GPS data to payload, if GPS is present and has a fix [default]
|
||||||
|
|
||||||
0x04 set display on/off
|
0x04 set display on/off
|
||||||
|
|
||||||
@ -144,7 +214,8 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
|||||||
0 = ADR off
|
0 = ADR off
|
||||||
1 = ADR on [default]
|
1 = ADR on [default]
|
||||||
|
|
||||||
note: set ADR to off, if device is moving, set to on, if not.
|
Note: set ADR to off, if device is moving, set to on, if not.
|
||||||
|
If ADR is set to on, SF value is shown inverted on display.
|
||||||
|
|
||||||
0x08 do nothing
|
0x08 do nothing
|
||||||
|
|
||||||
@ -156,77 +227,81 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
|||||||
1 = reset MAC counter to zero
|
1 = reset MAC counter to zero
|
||||||
2 = reset device to factory settings
|
2 = reset device to factory settings
|
||||||
|
|
||||||
0x0A set payload send cycle
|
0x0A set LoRaWAN payload send cycle
|
||||||
|
|
||||||
0 ... 255 payload send cycle in seconds/2
|
0 ... 255 payload send cycle in seconds/2
|
||||||
e.g. 120 -> payload is transmitted each 240 seconds [default]
|
e.g. 120 -> payload is transmitted each 240 seconds [default]
|
||||||
|
|
||||||
0x0B set Wifi channel switch interval timer
|
0x0B set Wifi channel switch interval timer
|
||||||
|
|
||||||
0 ... 255 timeout for scanning 1 wifi channel in seconds/100
|
0 ... 255 duration for scanning a wifi channel in seconds/100
|
||||||
e.g. 50 -> each channel is scanned for 0,5 seconds [default]
|
e.g. 50 -> each channel is scanned for 500 milliseconds [default]
|
||||||
|
|
||||||
0x0C set BLE scan cycle timer
|
0x0C set Bluetooth channel switch interval timer
|
||||||
|
|
||||||
0 ... 255 duration of a BLE scan cycle in seconds
|
0 ... 255 duration for scanning a bluetooth advertising channel in seconds/100
|
||||||
e.g. 11 -> 1 cycle runs for 11 seconds [default]
|
e.g. 8 -> each channel is scanned for 80 milliseconds [default]
|
||||||
|
|
||||||
0x0D (NOT YET IMPLEMENTED) set BLE and WIFI vendorfilter mode
|
0x0D (NOT YET IMPLEMENTED) set BLE and WIFI vendorfilter mode
|
||||||
|
|
||||||
0 = disabled (use to count devices, not people)
|
0 = disabled (use to count devices, not people)
|
||||||
1 = enabled [default]
|
1 = enabled [default]
|
||||||
|
|
||||||
0x0E set BLE scan mode
|
0x0E set Bluetooth scanner
|
||||||
|
|
||||||
0 = disabled
|
0 = disabled
|
||||||
1 = enabled [default]
|
1 = enabled [default]
|
||||||
|
|
||||||
0x0F set WIFI antenna switch (works on LoPy/LoPy4 only)
|
0x0F set WIFI antenna switch (works on LoPy/LoPy4/FiPy only)
|
||||||
|
|
||||||
0 = internal antenna [default]
|
0 = internal antenna [default]
|
||||||
1 = external antenna
|
1 = external antenna
|
||||||
|
|
||||||
0x10 set RGB led luminosity (works on LoPy/LoPy4 and LoRaNode32 shield only)
|
0x10 set RGB led luminosity (works on LoPy/LoPy4/FiPy and LoRaNode32 shield only)
|
||||||
|
|
||||||
0 ... 100 percentage of luminosity (100% = full light)
|
0 ... 100 percentage of luminosity (100% = full light)
|
||||||
e.g. 50 -> 50% of luminosity [default]
|
e.g. 50 -> 50% of luminosity [default]
|
||||||
|
|
||||||
0x80 get device configuration
|
0x80 get device configuration
|
||||||
|
|
||||||
device answers with it's current configuration. The configuration is a C structure declared in file [globals.h](src/globals.h#L27-L44) with the following definition:
|
device answers with it's current configuration. The configuration is a C structure declared in file [globals.h](src/globals.h#L32-L50) with the following definition:
|
||||||
|
|
||||||
byte 1: Lora SF (7..12)
|
byte 1: Lora SF (7..12) [default 9]
|
||||||
byte 2: Lora TXpower (2..15)
|
byte 2: Lora TXpower (2..15) [default 15]
|
||||||
byte 3: Lora ADR (1=on, 0=off)
|
byte 3: Lora ADR (1=on, 0=off) [default 1]
|
||||||
byte 4: Screensaver status (1=on, 0=off)
|
byte 4: Screensaver status (1=on, 0=off) [default 0]
|
||||||
byte 5: Display status (1=on, 0=off)
|
byte 5: Display status (1=on, 0=off) [default 0]
|
||||||
byte 6: Counter mode (0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed)
|
byte 6: Counter mode (0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed) [default 0]
|
||||||
bytes 7-8: RSSI limiter threshold value (negative)
|
bytes 7-8: RSSI limiter threshold value (negative) [default 0]
|
||||||
byte 9: Payload send cycle in seconds/2 (0..255)
|
byte 9: Lora Payload send cycle in seconds/2 (0..255) [default 120]
|
||||||
byte 10: Wifi channel switch interval in seconds/100 (0..255)
|
byte 10: Wifi channel switch interval in seconds/100 (0..255) [default 50]
|
||||||
byte 11: BLE scan cycle duration in seconds (0..255)
|
byte 11: Bluetooth channel switch interval in seconds/100 (0..255) [efault 10]
|
||||||
byte 12: BLE scan mode (1=on, 0=0ff)
|
byte 12: Bluetooth scanner status (1=on, 0=0ff) [default 1]
|
||||||
byte 13: Wifi antenna switch (0=internal, 1=external)
|
byte 13: Wifi antenna switch (0=internal, 1=external) [default 0]
|
||||||
byte 14: Vendorfilter mode (0=disabled, 1=enabled)
|
byte 14: Vendorfilter mode (0=disabled, 1=enabled) [default 0]
|
||||||
byte 15: RGB LED luminosity (0..100 %)
|
byte 15: RGB LED luminosity (0..100 %) [default 30]
|
||||||
bytes 16-25: Software version (ASCII format)
|
byte 16: GPS send data mode (1=on, 0=ff) [default 1]
|
||||||
|
bytes 17-27: Software version (ASCII format, terminating with zero)
|
||||||
|
|
||||||
0x81 get device uptime
|
0x81 get device uptime
|
||||||
|
|
||||||
bytes 1-7: Uptime in seconds (little endian format)
|
bytes 1-8: Uptime in seconds (little endian format)
|
||||||
|
|
||||||
0x82 get device cpu temperature
|
0x82 get device cpu temperature
|
||||||
|
|
||||||
bytes 1-3: chip temperature in celsius (little endian format)
|
bytes 1-4: Chip temperature in degrees celsius (little endian format)
|
||||||
|
|
||||||
# RGB Led color description
|
0x83 get device battery voltage
|
||||||
|
|
||||||
Description of the RGB LED color (LoPy/LoPy4 and Lolin32 only):
|
bytes 1-2: Battery voltage in millivolt, 0 if unreadable (little endian format)
|
||||||
|
|
||||||
- Yellow quick blink: joining LoRaWAN network in progress or pending
|
0x84 get device GPS status
|
||||||
- Blue blink: LoRaWAN data transmit (including waiting for receive windows) in progress or pending
|
|
||||||
- Green each blink: seen a new Wifi device
|
bytes 1-4: Latitude
|
||||||
- Magenta each blink: seen a new BLE device
|
bytes 5-8: Longitude
|
||||||
|
byte 9-10: Number of satellites
|
||||||
|
byte 11-12: HDOP
|
||||||
|
bytes 13-14: altidute [meter]
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
@ -252,4 +327,7 @@ see file <A HREF="https://github.com/cyberman54/ESP32-Paxcounter/blob/master/LIC
|
|||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
|
|
||||||
Thanks to Charles Hallard (https://github.com/hallard) for major contributions to this project.
|
Thanks to
|
||||||
|
- [Oliver Brandmüller](https://github.com/spmrider) for idea and initial setup of this project
|
||||||
|
- [Charles Hallard](https://github.com/hallard) for major code contributions to this project
|
||||||
|
- [robbi5](https://github.com/robbi5) for the payload converter
|
||||||
|
104
platformio.ini
104
platformio.ini
@ -11,21 +11,28 @@
|
|||||||
|
|
||||||
; ---> SELECT TARGET PLATFORM HERE! <---
|
; ---> SELECT TARGET PLATFORM HERE! <---
|
||||||
[platformio]
|
[platformio]
|
||||||
env_default = heltec_wifi_lora_32
|
env_default = heltec
|
||||||
;env_default = ttgov1
|
;env_default = ttgov1
|
||||||
;env_default = ttgov2
|
;env_default = ttgov2
|
||||||
|
;env_default = ttgov21
|
||||||
|
;env_default = ttgobeam
|
||||||
;env_default = lopy
|
;env_default = lopy
|
||||||
;env_default = lopy4
|
;env_default = lopy4
|
||||||
;env_default = lolin32lite_lora
|
;env_default = fipy
|
||||||
;env_default = lolin32_lora
|
;env_default = lolin32lite
|
||||||
|
;env_default = lolin32
|
||||||
;
|
;
|
||||||
description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around.
|
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]
|
[common_env_data]
|
||||||
|
platform_espressif32 = espressif32@>=1.0.2
|
||||||
|
board_build.partitions = no_ota.csv
|
||||||
lib_deps_display =
|
lib_deps_display =
|
||||||
U8g2@>=2.22.14
|
U8g2@>=2.22.14
|
||||||
lib_deps_rgbled =
|
lib_deps_rgbled =
|
||||||
SmartLeds
|
SmartLeds@>=1.1.3
|
||||||
|
lib_deps_gps =
|
||||||
|
TinyGPSPlus@>=1.0.2
|
||||||
build_flags =
|
build_flags =
|
||||||
; we need build_flag for logging, otherwise we can't use ESP_LOGx in arduino framework
|
; we need build_flag for logging, otherwise we can't use ESP_LOGx in arduino framework
|
||||||
; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <---
|
; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <---
|
||||||
@ -40,93 +47,132 @@ build_flags =
|
|||||||
-D_lmic_config_h_
|
-D_lmic_config_h_
|
||||||
-include "src/paxcounter.conf"
|
-include "src/paxcounter.conf"
|
||||||
|
|
||||||
[env:heltec_wifi_lora_32]
|
[env:heltec]
|
||||||
platform = espressif32
|
platform = ${common_env_data.platform_espressif32}
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = heltec_wifi_lora_32
|
board = heltec_wifi_lora_32
|
||||||
monitor_baud = 115200
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
upload_speed = 115200
|
upload_speed = 115200
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps_display}
|
${common_env_data.lib_deps_display}
|
||||||
build_flags =
|
build_flags =
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
-Dheltec_wifi_lora_32
|
|
||||||
-include "src/hal/heltec.h"
|
-include "src/hal/heltec.h"
|
||||||
|
|
||||||
[env:ttgov1]
|
[env:ttgov1]
|
||||||
platform = espressif32
|
platform = ${common_env_data.platform_espressif32}
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
monitor_baud = 115200
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
upload_speed = 115200
|
upload_speed = 115200
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps_display}
|
${common_env_data.lib_deps_display}
|
||||||
build_flags =
|
build_flags =
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
-Dttgov1
|
|
||||||
-include "src/hal/ttgov1.h"
|
-include "src/hal/ttgov1.h"
|
||||||
|
|
||||||
[env:ttgov2]
|
[env:ttgov2]
|
||||||
platform = espressif32
|
platform = ${common_env_data.platform_espressif32}
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
monitor_baud = 115200
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps_display}
|
${common_env_data.lib_deps_display}
|
||||||
build_flags =
|
build_flags =
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
-Dttgov2
|
|
||||||
-include "src/hal/ttgov2.h"
|
-include "src/hal/ttgov2.h"
|
||||||
|
|
||||||
[env:lopy]
|
[env:ttgov21]
|
||||||
platform = espressif32
|
platform = ${common_env_data.platform_espressif32}
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
monitor_baud = 115200
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
|
upload_speed = 921600
|
||||||
|
lib_deps =
|
||||||
|
${common_env_data.lib_deps_display}
|
||||||
|
build_flags =
|
||||||
|
${common_env_data.build_flags}
|
||||||
|
-include "src/hal/ttgov21.h"
|
||||||
|
|
||||||
|
[env:ttgobeam]
|
||||||
|
platform = ${common_env_data.platform_espressif32}
|
||||||
|
framework = arduino
|
||||||
|
board = esp32dev
|
||||||
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
|
upload_speed = 921600
|
||||||
|
lib_deps =
|
||||||
|
${common_env_data.lib_deps_gps}
|
||||||
|
build_flags =
|
||||||
|
${common_env_data.build_flags}
|
||||||
|
-include "src/hal/ttgobeam.h"
|
||||||
|
|
||||||
|
[env:fipy]
|
||||||
|
platform = espressif32@1.0.1
|
||||||
|
framework = arduino
|
||||||
|
board = esp32dev
|
||||||
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
|
upload_speed = 921600
|
||||||
|
lib_deps =
|
||||||
|
${common_env_data.lib_deps_rgbled}
|
||||||
|
build_flags =
|
||||||
|
${common_env_data.build_flags}
|
||||||
|
-include "src/hal/fipy.h"
|
||||||
|
|
||||||
|
[env:lopy]
|
||||||
|
platform = ${common_env_data.platform_espressif32}
|
||||||
|
framework = arduino
|
||||||
|
board = esp32dev
|
||||||
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps_rgbled}
|
${common_env_data.lib_deps_rgbled}
|
||||||
build_flags =
|
build_flags =
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
-Dlopy
|
|
||||||
-include "src/hal/lopy.h"
|
-include "src/hal/lopy.h"
|
||||||
|
|
||||||
[env:lopy4]
|
[env:lopy4]
|
||||||
platform = espressif32
|
platform = ${common_env_data.platform_espressif32}
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
monitor_baud = 115200
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps_rgbled}
|
${common_env_data.lib_deps_rgbled}
|
||||||
build_flags =
|
build_flags =
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
-Dlopy4
|
|
||||||
-include "src/hal/lopy4.h"
|
-include "src/hal/lopy4.h"
|
||||||
|
|
||||||
[env:lolin32lite_lora]
|
[env:lolin32lite]
|
||||||
platform = espressif32
|
platform = ${common_env_data.platform_espressif32}
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = lolin32
|
board = lolin32
|
||||||
monitor_baud = 115200
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
upload_speed = 256000
|
upload_speed = 256000
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps_rgbled}
|
${common_env_data.lib_deps_rgbled}
|
||||||
build_flags =
|
build_flags =
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
-Dlolin32lite_lora
|
|
||||||
-include "src/hal/lolin32lite_lora.h"
|
-include "src/hal/lolin32lite_lora.h"
|
||||||
|
|
||||||
[env:lolin32_lora]
|
[env:lolin32]
|
||||||
platform = espressif32
|
platform = ${common_env_data.platform_espressif32}
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = lolin32
|
board = lolin32
|
||||||
monitor_baud = 115200
|
board_build.partitions = ${common_env_data.board_build.partitions}
|
||||||
|
monitor_speed = 115200
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps_rgbled}
|
${common_env_data.lib_deps_rgbled}
|
||||||
build_flags =
|
build_flags =
|
||||||
${common_env_data.build_flags}
|
${common_env_data.build_flags}
|
||||||
-Dlolin32_lora
|
|
||||||
-include "src/hal/lolin32_lora.h"
|
-include "src/hal/lolin32_lora.h"
|
60
src/adcread.cpp
Normal file
60
src/adcread.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifdef HAS_BATTERY_PROBE
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
#include <driver/adc.h>
|
||||||
|
#include <esp_adc_cal.h>
|
||||||
|
|
||||||
|
#define DEFAULT_VREF 1100 // tbd: use adc2_vref_to_gpio() for better estimate
|
||||||
|
#define NO_OF_SAMPLES 64 // we do multisampling
|
||||||
|
|
||||||
|
// Local logging tag
|
||||||
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
|
static void print_char_val_type(esp_adc_cal_value_t val_type) {
|
||||||
|
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||||
|
ESP_LOGI(TAG,
|
||||||
|
"ADC characterization based on Two Point values stored in eFuse");
|
||||||
|
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||||
|
ESP_LOGI(TAG,
|
||||||
|
"ADC characterization based on reference voltage stored in eFuse");
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "ADC characterization based on default reference voltage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t read_voltage(void) {
|
||||||
|
static const adc1_channel_t channel = HAS_BATTERY_PROBE;
|
||||||
|
static const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||||
|
static const adc_unit_t unit = ADC_UNIT_1;
|
||||||
|
|
||||||
|
// configure ADC1
|
||||||
|
ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12));
|
||||||
|
ESP_ERROR_CHECK(adc1_config_channel_atten(channel, atten));
|
||||||
|
|
||||||
|
// calibrate ADC1
|
||||||
|
esp_adc_cal_characteristics_t *adc_chars =
|
||||||
|
(esp_adc_cal_characteristics_t *)calloc(
|
||||||
|
1, sizeof(esp_adc_cal_characteristics_t));
|
||||||
|
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(
|
||||||
|
unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
|
||||||
|
print_char_val_type(val_type);
|
||||||
|
|
||||||
|
// multisample ADC1
|
||||||
|
uint32_t adc_reading = 0;
|
||||||
|
for (int i = 0; i < NO_OF_SAMPLES; i++) {
|
||||||
|
adc_reading += adc1_get_raw(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_reading /= NO_OF_SAMPLES;
|
||||||
|
|
||||||
|
// Convert adc_reading to voltage in mV
|
||||||
|
uint16_t voltage =
|
||||||
|
(uint16_t)esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
|
||||||
|
#ifdef BATT_FACTOR
|
||||||
|
voltage *= BATT_FACTOR;
|
||||||
|
#endif
|
||||||
|
ESP_LOGI(TAG, "Raw: %d / Voltage: %dmV", adc_reading, voltage);
|
||||||
|
return voltage;
|
||||||
|
}
|
||||||
|
#endif // HAS_BATTERY_PROBE
|
@ -1,16 +1,13 @@
|
|||||||
/* switches wifi antenna, if board has switch to select internal and external antenna */
|
/* switches wifi antenna, if board has switch internal / external antenna */
|
||||||
|
|
||||||
#ifdef HAS_ANTENNA_SWITCH
|
#ifdef HAS_ANTENNA_SWITCH
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char *TAG = "antenna";
|
static const char TAG[] = "wifi";
|
||||||
|
|
||||||
typedef enum {
|
typedef enum { ANTENNA_INT = 0, ANTENNA_EXT } antenna_type_t;
|
||||||
ANTENNA_INT = 0,
|
|
||||||
ANTENNA_EXT
|
|
||||||
} antenna_type_t;
|
|
||||||
|
|
||||||
void antenna_init(void) {
|
void antenna_init(void) {
|
||||||
gpio_config_t gpioconf = {.pin_bit_mask = 1ull << HAS_ANTENNA_SWITCH,
|
gpio_config_t gpioconf = {.pin_bit_mask = 1ull << HAS_ANTENNA_SWITCH,
|
||||||
@ -21,7 +18,7 @@ void antenna_init(void) {
|
|||||||
gpio_config(&gpioconf);
|
gpio_config(&gpioconf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void antenna_select (const uint8_t _ant) {
|
void antenna_select(const uint8_t _ant) {
|
||||||
if (HAS_ANTENNA_SWITCH < 32) {
|
if (HAS_ANTENNA_SWITCH < 32) {
|
||||||
if (_ant == ANTENNA_EXT) {
|
if (_ant == ANTENNA_EXT) {
|
||||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1 << HAS_ANTENNA_SWITCH);
|
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1 << HAS_ANTENNA_SWITCH);
|
||||||
|
346
src/blecsan.cpp
346
src/blecsan.cpp
@ -14,21 +14,17 @@ https://github.com/nkolban/esp32-snippets/tree/master/BLE/scanner
|
|||||||
#include <esp_blufi_api.h> // needed for BLE_ADDR types, do not remove
|
#include <esp_blufi_api.h> // needed for BLE_ADDR types, do not remove
|
||||||
#include <bt_types.h>
|
#include <bt_types.h>
|
||||||
|
|
||||||
#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
|
#define BT_BD_ADDR_HEX(addr) \
|
||||||
|
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
|
||||||
|
|
||||||
// local Tag for logging
|
// local Tag for logging
|
||||||
static const char *TAG = "bt_loop";
|
static const char TAG[] = "bluetooth";
|
||||||
|
|
||||||
// defined in macsniff.cpp
|
// defined in macsniff.cpp
|
||||||
bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type);
|
bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type);
|
||||||
|
|
||||||
// Prototypes
|
const char *bt_addr_t_to_string(esp_ble_addr_type_t type) {
|
||||||
static const char *bt_addr_t_to_string(esp_ble_addr_type_t type);
|
switch (type) {
|
||||||
static const char *btsig_gap_type(uint32_t gap_type);
|
|
||||||
static void gap_callback_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
|
|
||||||
|
|
||||||
static const char *bt_addr_t_to_string(esp_ble_addr_type_t type) {
|
|
||||||
switch(type) {
|
|
||||||
case BLE_ADDR_TYPE_PUBLIC:
|
case BLE_ADDR_TYPE_PUBLIC:
|
||||||
return "BLE_ADDR_TYPE_PUBLIC";
|
return "BLE_ADDR_TYPE_PUBLIC";
|
||||||
case BLE_ADDR_TYPE_RANDOM:
|
case BLE_ADDR_TYPE_RANDOM:
|
||||||
@ -42,126 +38,157 @@ static const char *bt_addr_t_to_string(esp_ble_addr_type_t type) {
|
|||||||
}
|
}
|
||||||
} // bt_addr_t_to_string
|
} // bt_addr_t_to_string
|
||||||
|
|
||||||
static const char *btsig_gap_type(uint32_t gap_type) {
|
const char *btsig_gap_type(uint32_t gap_type) {
|
||||||
switch (gap_type)
|
switch (gap_type) {
|
||||||
{
|
case 0x01:
|
||||||
case 0x01: return "Flags";
|
return "Flags";
|
||||||
case 0x02: return "Incomplete List of 16-bit Service Class UUIDs";
|
case 0x02:
|
||||||
case 0x03: return "Complete List of 16-bit Service Class UUIDs";
|
return "Incomplete List of 16-bit Service Class UUIDs";
|
||||||
case 0x04: return "Incomplete List of 32-bit Service Class UUIDs";
|
case 0x03:
|
||||||
case 0x05: return "Complete List of 32-bit Service Class UUIDs";
|
return "Complete List of 16-bit Service Class UUIDs";
|
||||||
case 0x06: return "Incomplete List of 128-bit Service Class UUIDs";
|
case 0x04:
|
||||||
case 0x07: return "Complete List of 128-bit Service Class UUIDs";
|
return "Incomplete List of 32-bit Service Class UUIDs";
|
||||||
case 0x08: return "Shortened Local Name";
|
case 0x05:
|
||||||
case 0x09: return "Complete Local Name";
|
return "Complete List of 32-bit Service Class UUIDs";
|
||||||
case 0x0A: return "Tx Power Level";
|
case 0x06:
|
||||||
case 0x0D: return "Class of Device";
|
return "Incomplete List of 128-bit Service Class UUIDs";
|
||||||
case 0x0E: return "Simple Pairing Hash C/C-192";
|
case 0x07:
|
||||||
case 0x0F: return "Simple Pairing Randomizer R/R-192";
|
return "Complete List of 128-bit Service Class UUIDs";
|
||||||
case 0x10: return "Device ID/Security Manager TK Value";
|
case 0x08:
|
||||||
case 0x11: return "Security Manager Out of Band Flags";
|
return "Shortened Local Name";
|
||||||
case 0x12: return "Slave Connection Interval Range";
|
case 0x09:
|
||||||
case 0x14: return "List of 16-bit Service Solicitation UUIDs";
|
return "Complete Local Name";
|
||||||
case 0x1F: return "List of 32-bit Service Solicitation UUIDs";
|
case 0x0A:
|
||||||
case 0x15: return "List of 128-bit Service Solicitation UUIDs";
|
return "Tx Power Level";
|
||||||
case 0x16: return "Service Data - 16-bit UUID";
|
case 0x0D:
|
||||||
case 0x20: return "Service Data - 32-bit UUID";
|
return "Class of Device";
|
||||||
case 0x21: return "Service Data - 128-bit UUID";
|
case 0x0E:
|
||||||
case 0x22: return "LE Secure Connections Confirmation Value";
|
return "Simple Pairing Hash C/C-192";
|
||||||
case 0x23: return "LE Secure Connections Random Value";
|
case 0x0F:
|
||||||
case 0x24: return "URI";
|
return "Simple Pairing Randomizer R/R-192";
|
||||||
case 0x25: return "Indoor Positioning";
|
case 0x10:
|
||||||
case 0x26: return "Transport Discovery Data";
|
return "Device ID/Security Manager TK Value";
|
||||||
case 0x17: return "Public Target Address";
|
case 0x11:
|
||||||
case 0x18: return "Random Target Address";
|
return "Security Manager Out of Band Flags";
|
||||||
case 0x19: return "Appearance";
|
case 0x12:
|
||||||
case 0x1A: return "Advertising Interval";
|
return "Slave Connection Interval Range";
|
||||||
case 0x1B: return "LE Bluetooth Device Address";
|
case 0x14:
|
||||||
case 0x1C: return "LE Role";
|
return "List of 16-bit Service Solicitation UUIDs";
|
||||||
case 0x1D: return "Simple Pairing Hash C-256";
|
case 0x1F:
|
||||||
case 0x1E: return "Simple Pairing Randomizer R-256";
|
return "List of 32-bit Service Solicitation UUIDs";
|
||||||
case 0x3D: return "3D Information Data";
|
case 0x15:
|
||||||
case 0xFF: return "Manufacturer Specific Data";
|
return "List of 128-bit Service Solicitation UUIDs";
|
||||||
|
case 0x16:
|
||||||
|
return "Service Data - 16-bit UUID";
|
||||||
|
case 0x20:
|
||||||
|
return "Service Data - 32-bit UUID";
|
||||||
|
case 0x21:
|
||||||
|
return "Service Data - 128-bit UUID";
|
||||||
|
case 0x22:
|
||||||
|
return "LE Secure Connections Confirmation Value";
|
||||||
|
case 0x23:
|
||||||
|
return "LE Secure Connections Random Value";
|
||||||
|
case 0x24:
|
||||||
|
return "URI";
|
||||||
|
case 0x25:
|
||||||
|
return "Indoor Positioning";
|
||||||
|
case 0x26:
|
||||||
|
return "Transport Discovery Data";
|
||||||
|
case 0x17:
|
||||||
|
return "Public Target Address";
|
||||||
|
case 0x18:
|
||||||
|
return "Random Target Address";
|
||||||
|
case 0x19:
|
||||||
|
return "Appearance";
|
||||||
|
case 0x1A:
|
||||||
|
return "Advertising Interval";
|
||||||
|
case 0x1B:
|
||||||
|
return "LE Bluetooth Device Address";
|
||||||
|
case 0x1C:
|
||||||
|
return "LE Role";
|
||||||
|
case 0x1D:
|
||||||
|
return "Simple Pairing Hash C-256";
|
||||||
|
case 0x1E:
|
||||||
|
return "Simple Pairing Randomizer R-256";
|
||||||
|
case 0x3D:
|
||||||
|
return "3D Information Data";
|
||||||
|
case 0xFF:
|
||||||
|
return "Manufacturer Specific Data";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "Unknown type";
|
return "Unknown type";
|
||||||
}
|
}
|
||||||
} // btsig_gap_type
|
} // btsig_gap_type
|
||||||
|
|
||||||
|
// using IRAM_:ATTR here to speed up callback function
|
||||||
static void gap_callback_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
IRAM_ATTR void gap_callback_handler(esp_gap_ble_cb_event_t event,
|
||||||
{
|
esp_ble_gap_cb_param_t *param) {
|
||||||
esp_ble_gap_cb_param_t *p = (esp_ble_gap_cb_param_t *)param;
|
esp_ble_gap_cb_param_t *p = (esp_ble_gap_cb_param_t *)param;
|
||||||
esp_err_t status;
|
|
||||||
|
|
||||||
ESP_LOGD(tag, "BT payload rcvd -> type: 0x%.2x -> %s", *p->scan_rst.ble_adv, btsig_gap_type(*p->scan_rst.ble_adv));
|
ESP_LOGD(TAG, "BT payload rcvd -> type: 0x%.2x -> %s", *p->scan_rst.ble_adv,
|
||||||
|
btsig_gap_type(*p->scan_rst.ble_adv));
|
||||||
|
|
||||||
switch (event)
|
switch (event) {
|
||||||
{
|
|
||||||
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
|
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
|
||||||
{ // restart scan
|
// restart scan
|
||||||
status = esp_ble_gap_start_scanning(cfg.blescantime);
|
ESP_ERROR_CHECK(esp_ble_gap_start_scanning(BLESCANTIME));
|
||||||
if (status != ESP_OK)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_start_scanning: rc=%d", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESP_GAP_BLE_SCAN_RESULT_EVT:
|
case ESP_GAP_BLE_SCAN_RESULT_EVT:
|
||||||
{
|
// evaluate scan results
|
||||||
if ( p->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_CMPL_EVT) // Inquiry complete, scan is done
|
if (p->scan_rst.search_evt ==
|
||||||
|
ESP_GAP_SEARCH_INQ_CMPL_EVT) // Inquiry complete, scan is done
|
||||||
{ // restart scan
|
{ // restart scan
|
||||||
status = esp_ble_gap_start_scanning (cfg.blescantime);
|
ESP_ERROR_CHECK(esp_ble_gap_start_scanning(BLESCANTIME));
|
||||||
if (status != ESP_OK)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_start_scanning: rc=%d", status);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) // Inquiry result for a peer device
|
if (p->scan_rst.search_evt ==
|
||||||
|
ESP_GAP_SEARCH_INQ_RES_EVT) // Inquiry result for a peer device
|
||||||
{ // evaluate sniffed packet
|
{ // evaluate sniffed packet
|
||||||
ESP_LOGD(TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x", BT_BD_ADDR_HEX(p->scan_rst.bda));
|
ESP_LOGD(TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
ESP_LOGD(TAG, "Addr_type : %s", bt_addr_t_to_string(p->scan_rst.ble_addr_type));
|
BT_BD_ADDR_HEX(p->scan_rst.bda));
|
||||||
|
ESP_LOGD(TAG, "Addr_type : %s",
|
||||||
|
bt_addr_t_to_string(p->scan_rst.ble_addr_type));
|
||||||
ESP_LOGD(TAG, "RSSI : %d", p->scan_rst.rssi);
|
ESP_LOGD(TAG, "RSSI : %d", p->scan_rst.rssi);
|
||||||
|
|
||||||
if (!( cfg.rssilimit == 0 ) || (p->scan_rst.rssi > cfg.rssilimit )) { // rssi is negative value
|
if ((cfg.rssilimit) &&
|
||||||
ESP_LOGI(TAG, "BLTH RSSI %d -> ignoring (limit: %d)", p->scan_rst.rssi, cfg.rssilimit);
|
(p->scan_rst.rssi < cfg.rssilimit)) { // rssi is negative value
|
||||||
|
ESP_LOGI(TAG, "BLTH RSSI %d -> ignoring (limit: %d)", p->scan_rst.rssi,
|
||||||
|
cfg.rssilimit);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VENDORFILTER
|
#ifdef VENDORFILTER
|
||||||
|
|
||||||
if (p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RANDOM) goto skip;
|
if ((p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RANDOM) ||
|
||||||
if (p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RPA_RANDOM) goto skip;
|
(p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RPA_RANDOM)) {
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// add this device and show new count total if it was not previously added
|
|
||||||
if (cfg.blescan) // count only if BLE scan is enabled
|
|
||||||
mac_add((uint8_t *) p->scan_rst.bda, p->scan_rst.rssi, MAC_SNIFF_BLE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
skip:
|
|
||||||
ESP_LOGD(TAG, "BT device filtered");
|
ESP_LOGD(TAG, "BT device filtered");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// add this device and show new count total if it was not previously added
|
||||||
|
mac_add((uint8_t *)p->scan_rst.bda, p->scan_rst.rssi, MAC_SNIFF_BLE);
|
||||||
|
|
||||||
/* to be improved in vendorfilter if:
|
/* to be improved in vendorfilter if:
|
||||||
|
|
||||||
|
|
||||||
// you can search for elements in the payload using the
|
// you can search for elements in the payload using the
|
||||||
// function esp_ble_resolve_adv_data()
|
// function esp_ble_resolve_adv_data()
|
||||||
//
|
//
|
||||||
// Like this, that scans for the "Complete name" (looking inside the payload buffer)
|
// Like this, that scans for the "Complete name" (looking inside the
|
||||||
|
payload buffer)
|
||||||
// uint8_t len;
|
// uint8_t len;
|
||||||
// uint8_t *data = esp_ble_resolve_adv_data(p->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &len);
|
// uint8_t *data = esp_ble_resolve_adv_data(p->scan_rst.ble_adv,
|
||||||
|
ESP_BLE_AD_TYPE_NAME_CMPL, &len);
|
||||||
|
|
||||||
filter BLE devices using their advertisements to get filter alternative to vendor OUI
|
filter BLE devices using their advertisements to get filter alternative to
|
||||||
if vendorfiltering is on, we ...
|
vendor OUI if vendorfiltering is on, we ...
|
||||||
- want to count: mobile phones and tablets
|
- want to count: mobile phones and tablets
|
||||||
- don't want to count: beacons, peripherals (earphones, headsets, printers), cars and machines
|
- don't want to count: beacons, peripherals (earphones, headsets,
|
||||||
see
|
printers), cars and machines see
|
||||||
https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEAdvertisedDevice.cpp
|
https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEAdvertisedDevice.cpp
|
||||||
|
|
||||||
http://www.libelium.com/products/meshlium/smartphone-detection/
|
http://www.libelium.com/products/meshlium/smartphone-detection/
|
||||||
@ -170,15 +197,14 @@ static void gap_callback_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_pa
|
|||||||
|
|
||||||
https://www.bluetooth.com/specifications/assigned-numbers/baseband
|
https://www.bluetooth.com/specifications/assigned-numbers/baseband
|
||||||
|
|
||||||
"The Class of Device (CoD) in case of Bluetooth which allows us to differentiate the type of
|
"The Class of Device (CoD) in case of Bluetooth which allows us to
|
||||||
device (smartphone, handsfree, computer, LAN/network AP). With this parameter we can
|
differentiate the type of device (smartphone, handsfree, computer,
|
||||||
differentiate among pedestrians and vehicles."
|
LAN/network AP). With this parameter we can differentiate among
|
||||||
|
pedestrians and vehicles."
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
} // evaluate sniffed packet
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -186,113 +212,69 @@ static void gap_callback_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_pa
|
|||||||
}
|
}
|
||||||
} // gap_callback_handler
|
} // gap_callback_handler
|
||||||
|
|
||||||
|
esp_err_t register_ble_callback(void) {
|
||||||
esp_err_t register_ble_functionality(void)
|
|
||||||
{
|
|
||||||
esp_err_t status;
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Register GAP callback");
|
ESP_LOGI(TAG, "Register GAP callback");
|
||||||
|
|
||||||
// This function is called to occur gap event, such as scan result.
|
// This function is called to occur gap event, such as scan result.
|
||||||
//register the scan callback function to the gap module
|
// register the scan callback function to the gap module
|
||||||
status = esp_ble_gap_register_callback(gap_callback_handler);
|
ESP_ERROR_CHECK(esp_ble_gap_register_callback(&gap_callback_handler));
|
||||||
if (status != ESP_OK)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_register_callback: rc=%d", status);
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_ble_scan_params_t ble_scan_params =
|
static esp_ble_scan_params_t ble_scan_params = {
|
||||||
{
|
|
||||||
.scan_type = BLE_SCAN_TYPE_PASSIVE,
|
.scan_type = BLE_SCAN_TYPE_PASSIVE,
|
||||||
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
|
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
|
||||||
|
|
||||||
#ifdef VENDORFILTER
|
#ifdef VENDORFILTER
|
||||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR,
|
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR,
|
||||||
// ADV_IND, ADV_NONCONN_IND, ADV_SCAN_IND packets are used for broadcasting
|
// ADV_IND, ADV_NONCONN_IND, ADV_SCAN_IND packets are used for broadcasting
|
||||||
// data in broadcast applications (e.g., Beacons), so we don't want them in vendorfilter mode
|
// data in broadcast applications (e.g., Beacons), so we don't want them in
|
||||||
#else
|
// vendorfilter mode
|
||||||
|
#else
|
||||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||||
#endif
|
#endif
|
||||||
.scan_interval = (uint16_t) (BLESCANINTERVAL / 0.625), // Time = N * 0.625 msec
|
|
||||||
.scan_window = (uint16_t) (BLESCANWINDOW / 0.625) // Time = N * 0.625 msec
|
.scan_interval =
|
||||||
|
(uint16_t)(cfg.blescantime * 10 / 0.625), // Time = N * 0.625 msec
|
||||||
|
.scan_window = (uint16_t)(BLESCANWINDOW / 0.625) // Time = N * 0.625 msec
|
||||||
};
|
};
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Set GAP scan parameters");
|
ESP_LOGI(TAG, "Set GAP scan parameters");
|
||||||
|
|
||||||
// This function is called to set scan parameters.
|
// This function is called to set scan parameters.
|
||||||
status = esp_ble_gap_set_scan_params(&ble_scan_params);
|
ESP_ERROR_CHECK(esp_ble_gap_set_scan_params(&ble_scan_params));
|
||||||
if (status != ESP_OK)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_set_scan_params: rc=%d", status);
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ESP_OK ;
|
return ESP_OK;
|
||||||
}
|
|
||||||
|
|
||||||
|
} // register_ble_callback
|
||||||
|
|
||||||
// Main start code running in its own Xtask
|
void start_BLEscan(void) {
|
||||||
void bt_loop(void * pvParameters)
|
ESP_LOGI(TAG, "Initializing bluetooth scanner ...");
|
||||||
{
|
|
||||||
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
|
|
||||||
|
|
||||||
esp_err_t status;
|
|
||||||
|
|
||||||
// Initialize BT controller to allocate task and other resource.
|
// Initialize BT controller to allocate task and other resource.
|
||||||
ESP_LOGI(TAG, "Enabling Bluetooth Controller");
|
|
||||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||||
bt_cfg.controller_task_stack_size = 8192; // double BT stack size
|
bt_cfg.controller_task_stack_size =
|
||||||
|
BLESTACKSIZE; // set BT stack size to value configured in paxcounter.conf
|
||||||
|
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
|
||||||
|
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BTDM));
|
||||||
|
|
||||||
if (esp_bt_controller_init(&bt_cfg) != ESP_OK)
|
// Init and alloc the resource for bluetooth stack, must be done prior to
|
||||||
{
|
// every bluetooth stuff
|
||||||
ESP_LOGE(TAG, "Bluetooth controller initialize failed");
|
ESP_ERROR_CHECK(esp_bluedroid_init());
|
||||||
goto end;
|
ESP_ERROR_CHECK(esp_bluedroid_enable());
|
||||||
}
|
|
||||||
|
|
||||||
// Enable BT controller
|
// Register callback function for capturing bluetooth packets
|
||||||
if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK)
|
ESP_ERROR_CHECK(register_ble_callback());
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "Bluetooth controller enable failed");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
//esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); // gives 30KB more RAM for heap
|
ESP_LOGI(TAG, "Bluetooth scanner started");
|
||||||
|
} // start_BLEscan
|
||||||
|
|
||||||
// Init and alloc the resource for bluetooth, must be prior to every bluetooth stuff
|
void stop_BLEscan(void) {
|
||||||
ESP_LOGI(TAG, "Init Bluetooth stack");
|
ESP_LOGI(TAG, "Shutting down bluetooth scanner ...");
|
||||||
status = esp_bluedroid_init();
|
ESP_ERROR_CHECK(esp_ble_gap_register_callback(NULL));
|
||||||
if (status != ESP_OK)
|
ESP_ERROR_CHECK(esp_bluedroid_disable());
|
||||||
{
|
ESP_ERROR_CHECK(esp_bluedroid_deinit());
|
||||||
ESP_LOGE(TAG, "%s init bluetooth failed\n", __func__);
|
ESP_ERROR_CHECK(esp_bt_controller_disable());
|
||||||
goto end;
|
ESP_ERROR_CHECK(esp_bt_controller_deinit());
|
||||||
}
|
ESP_LOGI(TAG, "Bluetooth scanner stopped");
|
||||||
|
} // stop_BLEscan
|
||||||
// Enable bluetooth, must after esp_bluedroid_init()
|
|
||||||
status = esp_bluedroid_enable();
|
|
||||||
if (status != ESP_OK)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "%s enable bluetooth failed\n", __func__);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Register BLE functionality");
|
|
||||||
status = register_ble_functionality();
|
|
||||||
if (status != ESP_OK)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "Register BLE functionality failed");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
vTaskDelay(10/portTICK_PERIOD_MS); // reset watchdog
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
ESP_LOGI(TAG, "Terminating BT logging task");
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
|
|
||||||
} // bt_loop
|
|
||||||
|
|
||||||
#endif // BLECOUNTER
|
#endif // BLECOUNTER
|
@ -5,7 +5,7 @@
|
|||||||
#include <nvs_flash.h>
|
#include <nvs_flash.h>
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char *TAG = "configmanager";
|
static const char TAG[] = "flash";
|
||||||
|
|
||||||
nvs_handle my_handle;
|
nvs_handle my_handle;
|
||||||
|
|
||||||
@ -13,27 +13,31 @@ esp_err_t err;
|
|||||||
|
|
||||||
// defined in antenna.cpp
|
// defined in antenna.cpp
|
||||||
#ifdef HAS_ANTENNA_SWITCH
|
#ifdef HAS_ANTENNA_SWITCH
|
||||||
void antenna_select(const uint8_t _ant);
|
void antenna_select(const uint8_t _ant);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// populate cfg vars with factory settings
|
// populate cfg vars with factory settings
|
||||||
void defaultConfig() {
|
void defaultConfig() {
|
||||||
cfg.lorasf = LORASFDEFAULT; // 7-12, initial lora spreadfactor defined in paxcounter.conf
|
cfg.lorasf = LORASFDEFAULT; // 7-12, initial lora sf, see pacounter.conf
|
||||||
cfg.txpower = 15; // 2-15, lora tx power
|
cfg.txpower = 15; // 2-15, lora tx power
|
||||||
cfg.adrmode = 1; // 0=disabled, 1=enabled
|
cfg.adrmode = 1; // 0=disabled, 1=enabled
|
||||||
cfg.screensaver = 0; // 0=disabled, 1=enabled
|
cfg.screensaver = 0; // 0=disabled, 1=enabled
|
||||||
cfg.screenon = 1; // 0=disbaled, 1=enabled
|
cfg.screenon = 1; // 0=disabled, 1=enabled
|
||||||
cfg.countermode = 0; // 0=cyclic, 1=cumulative, 2=cyclic confirmed
|
cfg.countermode = 0; // 0=cyclic, 1=cumulative, 2=cyclic confirmed
|
||||||
cfg.rssilimit = 0; // threshold for rssilimiter, negative value!
|
cfg.rssilimit = 0; // threshold for rssilimiter, negative value!
|
||||||
cfg.sendcycle = SEND_SECS; // payload send cycle [seconds/2]
|
cfg.sendcycle = SEND_SECS; // payload send cycle [seconds/2]
|
||||||
cfg.wifichancycle = WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100]
|
cfg.wifichancycle =
|
||||||
cfg.blescantime = BLESCANTIME; // BLE scan cycle duration [seconds]
|
WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100]
|
||||||
|
cfg.blescantime =
|
||||||
|
BLESCANINTERVAL /
|
||||||
|
10; // BT channel scan cycle [seconds/100], default 1 (= 10ms)
|
||||||
cfg.blescan = 1; // 0=disabled, 1=enabled
|
cfg.blescan = 1; // 0=disabled, 1=enabled
|
||||||
cfg.wifiant = 0; // 0=internal, 1=external (for LoPy/LoPy4)
|
cfg.wifiant = 0; // 0=internal, 1=external (for LoPy/LoPy4)
|
||||||
cfg.vendorfilter = 1; // 0=disabled, 1=enabled
|
cfg.vendorfilter = 1; // 0=disabled, 1=enabled
|
||||||
cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
|
cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
|
||||||
|
cfg.gpsmode = 1; // 0=disabled, 1=enabled
|
||||||
|
|
||||||
strncpy( cfg.version, PROGVERSION, sizeof(cfg.version)-1 );
|
strncpy(cfg.version, PROGVERSION, sizeof(cfg.version) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_storage() {
|
void open_storage() {
|
||||||
@ -44,7 +48,7 @@ void open_storage() {
|
|||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
err = nvs_flash_init();
|
err = nvs_flash_init();
|
||||||
}
|
}
|
||||||
ESP_ERROR_CHECK( err );
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
// Open
|
// Open
|
||||||
ESP_LOGI(TAG, "Opening NVS");
|
ESP_LOGI(TAG, "Opening NVS");
|
||||||
@ -63,9 +67,10 @@ void eraseConfig() {
|
|||||||
nvs_erase_all(my_handle);
|
nvs_erase_all(my_handle);
|
||||||
nvs_commit(my_handle);
|
nvs_commit(my_handle);
|
||||||
nvs_close(my_handle);
|
nvs_close(my_handle);
|
||||||
ESP_LOGI(TAG, "Done");}
|
ESP_LOGI(TAG, "Done");
|
||||||
else {
|
} else {
|
||||||
ESP_LOGW(TAG, "NVS erase failed"); }
|
ESP_LOGW(TAG, "NVS erase failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save current configuration from RAM to NVRAM
|
// save current configuration from RAM to NVRAM
|
||||||
@ -78,54 +83,74 @@ void saveConfig() {
|
|||||||
size_t required_size;
|
size_t required_size;
|
||||||
char storedversion[10];
|
char storedversion[10];
|
||||||
|
|
||||||
if( nvs_get_str(my_handle, "version", storedversion, &required_size) != ESP_OK || strcmp(storedversion, cfg.version) != 0 )
|
if (nvs_get_str(my_handle, "version", storedversion, &required_size) !=
|
||||||
|
ESP_OK ||
|
||||||
|
strcmp(storedversion, cfg.version) != 0)
|
||||||
nvs_set_str(my_handle, "version", cfg.version);
|
nvs_set_str(my_handle, "version", cfg.version);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "lorasf", &flash8) != ESP_OK || flash8 != cfg.lorasf )
|
if (nvs_get_i8(my_handle, "lorasf", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.lorasf)
|
||||||
nvs_set_i8(my_handle, "lorasf", cfg.lorasf);
|
nvs_set_i8(my_handle, "lorasf", cfg.lorasf);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "txpower", &flash8) != ESP_OK || flash8 != cfg.txpower )
|
if (nvs_get_i8(my_handle, "txpower", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.txpower)
|
||||||
nvs_set_i8(my_handle, "txpower", cfg.txpower);
|
nvs_set_i8(my_handle, "txpower", cfg.txpower);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "adrmode", &flash8) != ESP_OK || flash8 != cfg.adrmode )
|
if (nvs_get_i8(my_handle, "adrmode", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.adrmode)
|
||||||
nvs_set_i8(my_handle, "adrmode", cfg.adrmode);
|
nvs_set_i8(my_handle, "adrmode", cfg.adrmode);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "screensaver", &flash8) != ESP_OK || flash8 != cfg.screensaver )
|
if (nvs_get_i8(my_handle, "screensaver", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.screensaver)
|
||||||
nvs_set_i8(my_handle, "screensaver", cfg.screensaver);
|
nvs_set_i8(my_handle, "screensaver", cfg.screensaver);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "screenon", &flash8) != ESP_OK || flash8 != cfg.screenon )
|
if (nvs_get_i8(my_handle, "screenon", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.screenon)
|
||||||
nvs_set_i8(my_handle, "screenon", cfg.screenon);
|
nvs_set_i8(my_handle, "screenon", cfg.screenon);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "countermode", &flash8) != ESP_OK || flash8 != cfg.countermode )
|
if (nvs_get_i8(my_handle, "countermode", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.countermode)
|
||||||
nvs_set_i8(my_handle, "countermode", cfg.countermode);
|
nvs_set_i8(my_handle, "countermode", cfg.countermode);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "sendcycle", &flash8) != ESP_OK || flash8 != cfg.sendcycle )
|
if (nvs_get_i8(my_handle, "sendcycle", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.sendcycle)
|
||||||
nvs_set_i8(my_handle, "sendcycle", cfg.sendcycle);
|
nvs_set_i8(my_handle, "sendcycle", cfg.sendcycle);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "wifichancycle", &flash8) != ESP_OK || flash8 != cfg.wifichancycle )
|
if (nvs_get_i8(my_handle, "wifichancycle", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.wifichancycle)
|
||||||
nvs_set_i8(my_handle, "wifichancycle", cfg.wifichancycle);
|
nvs_set_i8(my_handle, "wifichancycle", cfg.wifichancycle);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "blescantime", &flash8) != ESP_OK || flash8 != cfg.blescantime )
|
if (nvs_get_i8(my_handle, "blescantime", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.blescantime)
|
||||||
nvs_set_i8(my_handle, "blescantime", cfg.blescantime);
|
nvs_set_i8(my_handle, "blescantime", cfg.blescantime);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "blescanmode", &flash8) != ESP_OK || flash8 != cfg.blescan )
|
if (nvs_get_i8(my_handle, "blescanmode", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.blescan)
|
||||||
nvs_set_i8(my_handle, "blescanmode", cfg.blescan);
|
nvs_set_i8(my_handle, "blescanmode", cfg.blescan);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "wifiant", &flash8) != ESP_OK || flash8 != cfg.wifiant )
|
if (nvs_get_i8(my_handle, "wifiant", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.wifiant)
|
||||||
nvs_set_i8(my_handle, "wifiant", cfg.wifiant);
|
nvs_set_i8(my_handle, "wifiant", cfg.wifiant);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "vendorfilter", &flash8) != ESP_OK || flash8 != cfg.vendorfilter )
|
if (nvs_get_i8(my_handle, "vendorfilter", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.vendorfilter)
|
||||||
nvs_set_i8(my_handle, "vendorfilter", cfg.vendorfilter);
|
nvs_set_i8(my_handle, "vendorfilter", cfg.vendorfilter);
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "rgblum", &flash8) != ESP_OK || flash8 != cfg.rgblum )
|
if (nvs_get_i8(my_handle, "rgblum", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.rgblum)
|
||||||
nvs_set_i8(my_handle, "rgblum", cfg.rgblum);
|
nvs_set_i8(my_handle, "rgblum", cfg.rgblum);
|
||||||
|
|
||||||
if( nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK || flash16 != cfg.rssilimit )
|
if (nvs_get_i8(my_handle, "gpsmode", &flash8) != ESP_OK ||
|
||||||
|
flash8 != cfg.gpsmode)
|
||||||
|
nvs_set_i8(my_handle, "gpsmode", cfg.gpsmode);
|
||||||
|
|
||||||
|
if (nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK ||
|
||||||
|
flash16 != cfg.rssilimit)
|
||||||
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
|
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
|
||||||
|
|
||||||
err = nvs_commit(my_handle);
|
err = nvs_commit(my_handle);
|
||||||
nvs_close(my_handle);
|
nvs_close(my_handle);
|
||||||
if ( err == ESP_OK ) {
|
if (err == ESP_OK) {
|
||||||
ESP_LOGI(TAG, "Done");
|
ESP_LOGI(TAG, "Done");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "NVS config write failed");
|
ESP_LOGW(TAG, "NVS config write failed");
|
||||||
@ -148,19 +173,21 @@ void loadConfig() {
|
|||||||
ESP_LOGI(TAG, "Reading settings from NVS");
|
ESP_LOGI(TAG, "Reading settings from NVS");
|
||||||
open_storage();
|
open_storage();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGW(TAG,"Error (%d) opening NVS handle, storing defaults", err);
|
ESP_LOGW(TAG, "Error (%d) opening NVS handle, storing defaults", err);
|
||||||
saveConfig(); } // saves factory settings to NVRAM
|
saveConfig();
|
||||||
|
} // saves factory settings to NVRAM
|
||||||
else {
|
else {
|
||||||
int8_t flash8 = 0;
|
int8_t flash8 = 0;
|
||||||
int16_t flash16 = 0;
|
int16_t flash16 = 0;
|
||||||
size_t required_size;
|
size_t required_size;
|
||||||
|
|
||||||
// check if configuration stored in NVRAM matches PROGVERSION
|
// check if configuration stored in NVRAM matches PROGVERSION
|
||||||
if( nvs_get_str(my_handle, "version", NULL, &required_size) == ESP_OK ) {
|
if (nvs_get_str(my_handle, "version", NULL, &required_size) == ESP_OK) {
|
||||||
nvs_get_str(my_handle, "version", cfg.version, &required_size);
|
nvs_get_str(my_handle, "version", cfg.version, &required_size);
|
||||||
ESP_LOGI(TAG, "NVRAM settings version = %s", cfg.version);
|
ESP_LOGI(TAG, "NVRAM settings version = %s", cfg.version);
|
||||||
if (strcmp(cfg.version, PROGVERSION)) {
|
if (strcmp(cfg.version, PROGVERSION)) {
|
||||||
ESP_LOGI(TAG, "migrating NVRAM settings to new version %s", PROGVERSION);
|
ESP_LOGI(TAG, "migrating NVRAM settings to new version %s",
|
||||||
|
PROGVERSION);
|
||||||
nvs_close(my_handle);
|
nvs_close(my_handle);
|
||||||
migrateVersion();
|
migrateVersion();
|
||||||
}
|
}
|
||||||
@ -172,7 +199,7 @@ void loadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// overwrite defaults with valid values from NVRAM
|
// overwrite defaults with valid values from NVRAM
|
||||||
if( nvs_get_i8(my_handle, "lorasf", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "lorasf", &flash8) == ESP_OK) {
|
||||||
cfg.lorasf = flash8;
|
cfg.lorasf = flash8;
|
||||||
ESP_LOGI(TAG, "lorasf = %d", flash8);
|
ESP_LOGI(TAG, "lorasf = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +207,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "txpower", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "txpower", &flash8) == ESP_OK) {
|
||||||
cfg.txpower = flash8;
|
cfg.txpower = flash8;
|
||||||
ESP_LOGI(TAG, "txpower = %d", flash8);
|
ESP_LOGI(TAG, "txpower = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -188,7 +215,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "adrmode", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "adrmode", &flash8) == ESP_OK) {
|
||||||
cfg.adrmode = flash8;
|
cfg.adrmode = flash8;
|
||||||
ESP_LOGI(TAG, "adrmode = %d", flash8);
|
ESP_LOGI(TAG, "adrmode = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -196,7 +223,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "screensaver", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "screensaver", &flash8) == ESP_OK) {
|
||||||
cfg.screensaver = flash8;
|
cfg.screensaver = flash8;
|
||||||
ESP_LOGI(TAG, "screensaver = %d", flash8);
|
ESP_LOGI(TAG, "screensaver = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -204,7 +231,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "screenon", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "screenon", &flash8) == ESP_OK) {
|
||||||
cfg.screenon = flash8;
|
cfg.screenon = flash8;
|
||||||
ESP_LOGI(TAG, "screenon = %d", flash8);
|
ESP_LOGI(TAG, "screenon = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -212,7 +239,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "countermode", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "countermode", &flash8) == ESP_OK) {
|
||||||
cfg.countermode = flash8;
|
cfg.countermode = flash8;
|
||||||
ESP_LOGI(TAG, "countermode = %d", flash8);
|
ESP_LOGI(TAG, "countermode = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -220,7 +247,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "sendcycle", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "sendcycle", &flash8) == ESP_OK) {
|
||||||
cfg.sendcycle = flash8;
|
cfg.sendcycle = flash8;
|
||||||
ESP_LOGI(TAG, "sendcycle = %d", flash8);
|
ESP_LOGI(TAG, "sendcycle = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -228,7 +255,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "wifichancycle", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "wifichancycle", &flash8) == ESP_OK) {
|
||||||
cfg.wifichancycle = flash8;
|
cfg.wifichancycle = flash8;
|
||||||
ESP_LOGI(TAG, "wifichancycle = %d", flash8);
|
ESP_LOGI(TAG, "wifichancycle = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -236,7 +263,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "wifiant", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "wifiant", &flash8) == ESP_OK) {
|
||||||
cfg.wifiant = flash8;
|
cfg.wifiant = flash8;
|
||||||
ESP_LOGI(TAG, "wifiantenna = %d", flash8);
|
ESP_LOGI(TAG, "wifiantenna = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -244,7 +271,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "vendorfilter", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "vendorfilter", &flash8) == ESP_OK) {
|
||||||
cfg.vendorfilter = flash8;
|
cfg.vendorfilter = flash8;
|
||||||
ESP_LOGI(TAG, "vendorfilter = %d", flash8);
|
ESP_LOGI(TAG, "vendorfilter = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -252,7 +279,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "rgblum", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "rgblum", &flash8) == ESP_OK) {
|
||||||
cfg.rgblum = flash8;
|
cfg.rgblum = flash8;
|
||||||
ESP_LOGI(TAG, "rgbluminosity = %d", flash8);
|
ESP_LOGI(TAG, "rgbluminosity = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -260,7 +287,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "blescantime", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "blescantime", &flash8) == ESP_OK) {
|
||||||
cfg.blescantime = flash8;
|
cfg.blescantime = flash8;
|
||||||
ESP_LOGI(TAG, "blescantime = %d", flash8);
|
ESP_LOGI(TAG, "blescantime = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -268,7 +295,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i8(my_handle, "blescanmode", &flash8) == ESP_OK ) {
|
if (nvs_get_i8(my_handle, "blescanmode", &flash8) == ESP_OK) {
|
||||||
cfg.blescan = flash8;
|
cfg.blescan = flash8;
|
||||||
ESP_LOGI(TAG, "BLEscanmode = %d", flash8);
|
ESP_LOGI(TAG, "BLEscanmode = %d", flash8);
|
||||||
} else {
|
} else {
|
||||||
@ -276,7 +303,7 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nvs_get_i16(my_handle, "rssilimit", &flash16) == ESP_OK ) {
|
if (nvs_get_i16(my_handle, "rssilimit", &flash16) == ESP_OK) {
|
||||||
cfg.rssilimit = flash16;
|
cfg.rssilimit = flash16;
|
||||||
ESP_LOGI(TAG, "rssilimit = %d", flash16);
|
ESP_LOGI(TAG, "rssilimit = %d", flash16);
|
||||||
} else {
|
} else {
|
||||||
@ -284,13 +311,21 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nvs_get_i8(my_handle, "gpsmode", &flash8) == ESP_OK) {
|
||||||
|
cfg.gpsmode = flash8;
|
||||||
|
ESP_LOGI(TAG, "GPSmode = %d", flash8);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "GPSmode set to default %d", cfg.gpsmode);
|
||||||
|
saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
nvs_close(my_handle);
|
nvs_close(my_handle);
|
||||||
ESP_LOGI(TAG, "Done");
|
ESP_LOGI(TAG, "Done");
|
||||||
|
|
||||||
// put actions to be triggered after config loaded here
|
// put actions to be triggered after config loaded here
|
||||||
|
|
||||||
#ifdef HAS_ANTENNA_SWITCH // set antenna type, if device has one
|
#ifdef HAS_ANTENNA_SWITCH // set antenna type, if device has one
|
||||||
antenna_select(cfg.wifiant);
|
antenna_select(cfg.wifiant);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
src/configmanager.h
Normal file
8
src/configmanager.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef CONFIGMANAGER_H
|
||||||
|
#define CONFIGMANAGER_H
|
||||||
|
|
||||||
|
void eraseConfig(void);
|
||||||
|
void saveConfig(void);
|
||||||
|
void loadConfig(void);
|
||||||
|
|
||||||
|
#endif
|
@ -8,7 +8,12 @@
|
|||||||
|
|
||||||
// OLED Display
|
// OLED Display
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
#include <U8x8lib.h>
|
#include <U8x8lib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GPS
|
||||||
|
#ifdef HAS_GPS
|
||||||
|
#include <TinyGPS++.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// LMIC-Arduino LoRaWAN Stack
|
// LMIC-Arduino LoRaWAN Stack
|
||||||
@ -17,7 +22,7 @@
|
|||||||
|
|
||||||
// LED controls
|
// LED controls
|
||||||
#ifdef HAS_RGB_LED
|
#ifdef HAS_RGB_LED
|
||||||
#include <SmartLeds.h>
|
#include <SmartLeds.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "rgb_led.h"
|
#include "rgb_led.h"
|
||||||
@ -40,20 +45,30 @@ typedef struct {
|
|||||||
uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4)
|
uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4)
|
||||||
uint8_t vendorfilter; // 0=disabled, 1=enabled
|
uint8_t vendorfilter; // 0=disabled, 1=enabled
|
||||||
uint8_t rgblum; // RGB Led luminosity (0..100%)
|
uint8_t rgblum; // RGB Led luminosity (0..100%)
|
||||||
|
uint8_t gpsmode; // 0=disabled, 1=enabled
|
||||||
char version[10]; // Firmware version
|
char version[10]; // Firmware version
|
||||||
} configData_t;
|
} configData_t;
|
||||||
|
|
||||||
|
#ifdef HAS_GPS
|
||||||
|
typedef struct {
|
||||||
|
uint32_t latitude;
|
||||||
|
uint32_t longitude;
|
||||||
|
uint8_t satellites;
|
||||||
|
uint16_t hdop;
|
||||||
|
uint16_t altitude;
|
||||||
|
} gpsStatus_t;
|
||||||
|
extern gpsStatus_t gps_status; // struct for storing gps data
|
||||||
|
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
||||||
|
#endif
|
||||||
|
|
||||||
extern configData_t cfg;
|
extern configData_t cfg;
|
||||||
extern uint8_t mydata[];
|
|
||||||
extern uint64_t uptimecounter;
|
extern uint64_t uptimecounter;
|
||||||
extern osjob_t sendjob;
|
extern osjob_t sendjob, rcmdjob;
|
||||||
extern char display_lora[], display_lmic[];
|
extern char display_lora[], display_lmic[];
|
||||||
extern int countermode, screensaver, adrmode, lorasf, txpower, rlim;
|
extern int countermode, screensaver, adrmode, lorasf, txpower, rlim;
|
||||||
extern uint16_t macs_total, macs_wifi, macs_ble; // MAC counters
|
extern uint16_t macs_total, macs_wifi, macs_ble; // MAC counters
|
||||||
extern bool joinstate;
|
|
||||||
extern std::set<uint16_t> macs;
|
extern std::set<uint16_t> macs;
|
||||||
extern hw_timer_t * channelSwitch; // hardware timer used for wifi channel switching
|
extern hw_timer_t
|
||||||
|
*channelSwitch; // hardware timer used for wifi channel switching
|
||||||
#ifdef HAS_DISPLAY
|
extern xref2u1_t rcmd_data; // buffer for rcommand results size
|
||||||
extern HAS_DISPLAY u8x8;
|
extern u1_t rcmd_data_size; // buffer for rcommand results size
|
||||||
#endif
|
|
||||||
|
79
src/gpsread.cpp
Normal file
79
src/gpsread.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#ifdef HAS_GPS
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
// Local logging tag
|
||||||
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
|
// read GPS data and cast to global struct
|
||||||
|
void gps_read() {
|
||||||
|
gps_status.latitude = (uint32_t)(gps.location.lat() * 1000000);
|
||||||
|
gps_status.longitude = (uint32_t)(gps.location.lng() * 1000000);
|
||||||
|
gps_status.satellites = (uint8_t)gps.satellites.value();
|
||||||
|
gps_status.hdop = (uint16_t)gps.hdop.value();
|
||||||
|
gps_status.altitude = (uint16_t)gps.altitude.meters();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GPS serial feed FreeRTos Task
|
||||||
|
void gps_loop(void *pvParameters) {
|
||||||
|
|
||||||
|
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||||
|
|
||||||
|
// initialize and, if needed, configure, GPS
|
||||||
|
#if defined GPS_SERIAL
|
||||||
|
HardwareSerial GPS_Serial(1);
|
||||||
|
#elif defined GPS_I2C
|
||||||
|
// to be done
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
// after GPS function was disabled, close connect to GPS device
|
||||||
|
GPS_Serial.end();
|
||||||
|
|
||||||
|
#elif defined GPS_I2C
|
||||||
|
|
||||||
|
// I2C connect to GPS device with 100 kHz
|
||||||
|
Wire.begin(GPS_I2C_PINS, 100000);
|
||||||
|
Wire.beginTransmission(GPS_I2C_ADDRESS_WRITE);
|
||||||
|
Wire.write(0x00);
|
||||||
|
|
||||||
|
i2c_ret == Wire.beginTransmission(GPS_I2C_ADDRESS_READ);
|
||||||
|
if (i2c_ret == 0) { // check if device seen on i2c bus
|
||||||
|
while (cfg.gpsmode) {
|
||||||
|
// feed GPS decoder with serial NMEA data from GPS device
|
||||||
|
while (Wire.available()) {
|
||||||
|
Wire.requestFrom(GPS_I2C_ADDRESS_READ, 255);
|
||||||
|
gps.encode(Wire.read());
|
||||||
|
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// after GPS function was disabled, close connect to GPS device
|
||||||
|
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.setClock(400000); // Set back to 400KHz to speed up OLED
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||||
|
|
||||||
|
} // end of infinite loop
|
||||||
|
|
||||||
|
} // gps_loop()
|
||||||
|
|
||||||
|
#endif // HAS_GPS
|
19
src/hal/fipy.h
Normal file
19
src/hal/fipy.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Hardware related definitions for Pycom FiPy Board
|
||||||
|
|
||||||
|
#define CFG_sx1272_radio 1
|
||||||
|
#define HAS_LED NOT_A_PIN // FiPy has no on board LED, so we use RGB LED
|
||||||
|
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
|
||||||
|
|
||||||
|
// Hardware pin definitions for Pycom FiPy board
|
||||||
|
#define PIN_SPI_SS GPIO_NUM_18
|
||||||
|
#define PIN_SPI_MOSI GPIO_NUM_27
|
||||||
|
#define PIN_SPI_MISO GPIO_NUM_19
|
||||||
|
#define PIN_SPI_SCK GPIO_NUM_5
|
||||||
|
#define RST LMIC_UNUSED_PIN
|
||||||
|
#define DIO0 GPIO_NUM_23 // LoRa IRQ
|
||||||
|
#define DIO1 GPIO_NUM_23 // workaround
|
||||||
|
#define DIO2 LMIC_UNUSED_PIN
|
||||||
|
|
||||||
|
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
||||||
|
#define HAS_ANTENNA_SWITCH GPIO_NUM_21 // pin for switching wifi antenna
|
||||||
|
#define WIFI_ANTENNA 0 // 0 = internal, 1 = external
|
@ -8,18 +8,18 @@
|
|||||||
#define HAS_BUTTON GPIO_NUM_0 // button "PROG" on board
|
#define HAS_BUTTON GPIO_NUM_0 // button "PROG" on board
|
||||||
|
|
||||||
// re-define pin definitions of pins_arduino.h
|
// re-define pin definitions of pins_arduino.h
|
||||||
#define PIN_SPI_SS 18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
|
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
|
||||||
#define PIN_SPI_MOSI 27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
|
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
|
||||||
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
|
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
|
||||||
#define PIN_SPI_SCK 5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
|
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
|
||||||
|
|
||||||
// non arduino pin definitions
|
// non arduino pin definitions
|
||||||
#define RST 14 // ESP32 GPIO14 (Pin14) -- SX1276 NRESET (Pin7) Reset Trigger Input
|
#define RST GPIO_NUM_14 // ESP32 GPIO14 (Pin14) -- SX1276 NRESET (Pin7) Reset Trigger Input
|
||||||
#define DIO0 26 // ESP32 GPIO26 (Pin15) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
|
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 (Pin15) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
|
||||||
#define DIO1 33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
|
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
|
||||||
#define DIO2 LMIC_UNUSED_PIN // 32 ESP32 GPIO32 (Pin12) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
|
#define DIO2 LMIC_UNUSED_PIN // 32 ESP32 GPIO32 (Pin12) -- 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
|
// Hardware pin definitions for Heltec LoRa-32 Board with OLED SSD1306 I2C Display
|
||||||
#define OLED_RST 16 // ESP32 GPIO16 (Pin16) -- SD1306 RST
|
#define OLED_RST GPIO_NUM_16 // ESP32 GPIO16 (Pin16) -- SD1306 RST
|
||||||
#define OLED_SDA 4 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2
|
#define OLED_SDA GPIO_NUM_4 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2
|
||||||
#define OLED_SCL 15 // ESP32 GPIO15 (Pin15) -- SD1306 D0
|
#define OLED_SCL GPIO_NUM_15 // ESP32 GPIO15 (Pin15) -- SD1306 D0
|
||||||
|
@ -2,17 +2,26 @@
|
|||||||
|
|
||||||
#define CFG_sx1272_radio 1
|
#define CFG_sx1272_radio 1
|
||||||
#define HAS_LED NOT_A_PIN // LoPy4 has no on board LED, so we use RGB LED on LoPy4
|
#define HAS_LED NOT_A_PIN // LoPy4 has no on board LED, so we use RGB LED on LoPy4
|
||||||
#define HAS_RGB_LED 0 // WS2812B RGB LED on GPIO0
|
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
|
||||||
|
|
||||||
|
// !!EXPERIMENTAL - not tested yet!!
|
||||||
|
// uncomment this only if your LoPy lives on a Pytrack expansion board with GPS
|
||||||
|
// see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf
|
||||||
|
//#define HAS_GPS 1
|
||||||
|
//#define GPS_I2C_PINS GPIO_NUM_9, GPIO_NUM_8 // SDA, SCL
|
||||||
|
//#define GPS_I2C_ADDRESS_READ 0x21
|
||||||
|
//#define GPS_I2C_ADDRESS_WRITE 0x20
|
||||||
|
//#define HAS_BUTTON GPIO_NUM_4
|
||||||
|
|
||||||
// Hardware pin definitions for Pycom LoPy board
|
// Hardware pin definitions for Pycom LoPy board
|
||||||
#define PIN_SPI_SS 17
|
#define PIN_SPI_SS GPIO_NUM_17
|
||||||
#define PIN_SPI_MOSI 27
|
#define PIN_SPI_MOSI GPIO_NUM_27
|
||||||
#define PIN_SPI_MISO 19
|
#define PIN_SPI_MISO GPIO_NUM_19
|
||||||
#define PIN_SPI_SCK 5
|
#define PIN_SPI_SCK GPIO_NUM_5
|
||||||
#define RST 18
|
#define RST GPIO_NUM_18
|
||||||
#define DIO0 23 // LoRa IRQ
|
#define DIO0 GPIO_NUM_23 // LoRa IRQ
|
||||||
#define DIO1 23 // workaround
|
#define DIO1 GPIO_NUM_23 // workaround
|
||||||
#define DIO2 LMIC_UNUSED_PIN // 23 workaround
|
#define DIO2 LMIC_UNUSED_PIN
|
||||||
|
|
||||||
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
||||||
#define HAS_ANTENNA_SWITCH 16 // pin for switching wifi antenna
|
#define HAS_ANTENNA_SWITCH 16 // pin for switching wifi antenna
|
||||||
|
@ -2,17 +2,26 @@
|
|||||||
|
|
||||||
#define CFG_sx1276_radio 1
|
#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_LED NOT_A_PIN // LoPy4 has no on board LED, so we use RGB LED on LoPy4
|
||||||
#define HAS_RGB_LED 0 // WS2812B RGB LED on GPIO0
|
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
|
||||||
|
|
||||||
|
// !!EXPERIMENTAL - not tested yet!!f
|
||||||
|
// uncomment this only if your LoPy lives on a Pytrack expansion board with GPS
|
||||||
|
// see http://www.quectel.com/UploadImage/Downlad/Quectel_L76-L_I2C_Application_Note_V1.0.pdf
|
||||||
|
//#define HAS_GPS 1
|
||||||
|
//#define GPS_I2C_PINS GPIO_NUM_9, GPIO_NUM_8 // SDA, SCL
|
||||||
|
//#define GPS_I2C_ADDRESS_READ 0x21
|
||||||
|
//#define GPS_I2C_ADDRESS_WRITE 0x20
|
||||||
|
//#define HAS_BUTTON GPIO_NUM_4
|
||||||
|
|
||||||
// Hardware pin definitions for Pycom LoPy4 board
|
// Hardware pin definitions for Pycom LoPy4 board
|
||||||
#define PIN_SPI_SS 18
|
#define PIN_SPI_SS GPIO_NUM_18
|
||||||
#define PIN_SPI_MOSI 27
|
#define PIN_SPI_MOSI GPIO_NUM_27
|
||||||
#define PIN_SPI_MISO 19
|
#define PIN_SPI_MISO GPIO_NUM_19
|
||||||
#define PIN_SPI_SCK 5
|
#define PIN_SPI_SCK GPIO_NUM_5
|
||||||
#define RST LMIC_UNUSED_PIN
|
#define RST LMIC_UNUSED_PIN
|
||||||
#define DIO0 23 // LoRa IRQ
|
#define DIO0 GPIO_NUM_23 // LoRa IRQ
|
||||||
#define DIO1 23 // workaround
|
#define DIO1 GPIO_NUM_23 // workaround
|
||||||
#define DIO2 LMIC_UNUSED_PIN // 23 workaround
|
#define DIO2 LMIC_UNUSED_PIN
|
||||||
|
|
||||||
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
||||||
#define HAS_ANTENNA_SWITCH 21 // pin for switching wifi antenna
|
#define HAS_ANTENNA_SWITCH 21 // pin for switching wifi antenna
|
||||||
|
22
src/hal/ttgobeam.h
Normal file
22
src/hal/ttgobeam.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Hardware related definitions for TTGO T-Beam board
|
||||||
|
|
||||||
|
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
|
||||||
|
|
||||||
|
#define HAS_LED GPIO_NUM_21 // on board green LED_G1
|
||||||
|
//#define HAS_BUTTON GPIO_NUM_39 // on board button "BOOT" (next to reset button) !! seems not to work!!
|
||||||
|
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||||
|
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
|
||||||
|
#define HAS_GPS 1 // use on board GPS
|
||||||
|
#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M or 7M with default configuration
|
||||||
|
|
||||||
|
// 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
|
||||||
|
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0
|
||||||
|
#define DIO1 GPIO_NUM_32 // Lora1 <-> HPD13A IO1 // !! NEEDS EXTERNAL WIRING !!
|
||||||
|
#define DIO2 LMIC_UNUSED_PIN // Lora2 <-> HPD13A IO2 // not needed for LoRa
|
@ -9,18 +9,18 @@
|
|||||||
#define HAS_BUTTON GPIO_NUM_0 // button "PRG" on board
|
#define HAS_BUTTON GPIO_NUM_0 // button "PRG" on board
|
||||||
|
|
||||||
// re-define pin definitions of pins_arduino.h
|
// re-define pin definitions of pins_arduino.h
|
||||||
#define PIN_SPI_SS 18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
|
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
|
||||||
#define PIN_SPI_MOSI 27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
|
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
|
||||||
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
|
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
|
||||||
#define PIN_SPI_SCK 5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
|
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
|
||||||
|
|
||||||
// non arduino pin definitions
|
// non arduino pin definitions
|
||||||
#define RST 14 // ESP32 GPIO14 (Pin14) -- SX1276 NRESET (Pin7) Reset Trigger Input
|
#define RST GPIO_NUM_14 // ESP32 GPIO14 (Pin14) -- SX1276 NRESET (Pin7) Reset Trigger Input
|
||||||
#define DIO0 26 // ESP32 GPIO26 (Pin15) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
|
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 (Pin15) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
|
||||||
#define DIO1 33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
|
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
|
||||||
#define DIO2 LMIC_UNUSED_PIN // 32 ESP32 GPIO32 (Pin12) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
|
#define DIO2 LMIC_UNUSED_PIN // 32 ESP32 GPIO32 (Pin12) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
|
||||||
|
|
||||||
// Hardware pin definitions for TTGOv1 Board with OLED SSD1306 I2C Display
|
// Hardware pin definitions for TTGOv1 Board with OLED SSD1306 I2C Display
|
||||||
#define OLED_RST 16 // ESP32 GPIO16 (Pin16) -- SD1306 Reset
|
#define OLED_RST GPIO_NUM_16 // ESP32 GPIO16 (Pin16) -- SD1306 Reset
|
||||||
#define OLED_SDA 4 // ESP32 GPIO4 (Pin4) -- SD1306 Data
|
#define OLED_SDA GPIO_NUM_4 // ESP32 GPIO4 (Pin4) -- SD1306 Data
|
||||||
#define OLED_SCL 15 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
|
#define OLED_SCL GPIO_NUM_15 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
|
||||||
|
@ -10,21 +10,21 @@
|
|||||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||||
|
|
||||||
// re-define pin definitions of pins_arduino.h
|
// re-define pin definitions of pins_arduino.h
|
||||||
#define PIN_SPI_SS 18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input
|
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input
|
||||||
#define PIN_SPI_MOSI 27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input
|
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input
|
||||||
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output
|
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output
|
||||||
#define PIN_SPI_SCK 5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input
|
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input
|
||||||
|
|
||||||
// non arduino pin definitions
|
// non arduino pin definitions
|
||||||
#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN
|
#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN
|
||||||
#define DIO0 26 // ESP32 GPIO26 wired on PCB to HPD13A
|
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 wired on PCB to HPD13A
|
||||||
#define DIO1 33 // HPDIO1 on pcb, needs to be wired external to GPIO33
|
#define DIO1 GPIO_NUM_33 // HPDIO1 on pcb, needs to be wired external to GPIO33
|
||||||
#define DIO2 LMIC_UNUSED_PIN // 32 HPDIO2 on pcb, needs to be wired external to GPIO32 (not necessary for LoRa, only FSK)
|
#define DIO2 LMIC_UNUSED_PIN // 32 HPDIO2 on pcb, needs to be wired external to GPIO32 (not necessary for LoRa, only FSK)
|
||||||
|
|
||||||
// Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display
|
// 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_RST U8X8_PIN_NONE // connected to CPU RST/EN
|
||||||
#define OLED_SDA 21 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2
|
#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2
|
||||||
#define OLED_SCL 22 // ESP32 GPIO15 (Pin15) -- SD1306 D0
|
#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO15 (Pin15) -- SD1306 D0
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
26
src/hal/ttgov21.h
Normal file
26
src/hal/ttgov21.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Hardware related definitions for TTGO V2.1 Board
|
||||||
|
|
||||||
|
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
|
||||||
|
|
||||||
|
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||||
|
#define DISPLAY_FLIP 1 // rotated display
|
||||||
|
#define HAS_LED GPIO_NUM_23 // green on board LED_G3 (not in initial board version)
|
||||||
|
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||||
|
#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
|
||||||
|
#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 GPIO4 (Pin4) -- SD1306 D1+D2
|
||||||
|
#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO15 (Pin15) -- SD1306 D0
|
@ -1,26 +1,31 @@
|
|||||||
/************************************************************
|
/************************************************************
|
||||||
* LMIC LoRaWAN configuration
|
* LMIC LoRaWAN configuration
|
||||||
*
|
*
|
||||||
* Read the values from TTN console (or whatever applies)
|
* Read the values from TTN console (or whatever applies), insert them here,
|
||||||
|
* and rename this file to src/loraconf.h
|
||||||
|
*
|
||||||
|
* Note that DEVEUI, APPEUI and APPKEY should all be specified in MSB format.
|
||||||
|
* (This is different from standard LMIC-Arduino which expects DEVEUI and APPEUI
|
||||||
|
* in LSB format.)
|
||||||
|
|
||||||
|
* Set your DEVEUI here, if you have one. You can leave this untouched,
|
||||||
|
* then the DEVEUI will be generated during runtime from device's MAC adress
|
||||||
|
* and will be displayed on device's screen as well as on serial console.
|
||||||
|
*
|
||||||
|
* NOTE: Use MSB format (as displayed in TTN console, so you can cut & paste
|
||||||
|
* from there)
|
||||||
|
* For TTN, APPEUI in MSB format always starts with 0x70, 0xB3, 0xD5
|
||||||
|
*
|
||||||
|
* Note: If using a board with Microchip 24AA02E64 Uinique ID for deveui,
|
||||||
|
* the DEVEUI will be overwriten by the one contained in the Microchip module
|
||||||
*
|
*
|
||||||
************************************************************/
|
************************************************************/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
/*
|
static const u1_t DEVEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
// Set your DEVEUI here, if you have one. You can leave this untouched,
|
static const u1_t APPEUI[8] = {0x70, 0xB3, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
// then the DEVEUI will be generated during runtime from device's MAC adress
|
|
||||||
// Note: Use same format as in TTN console (cut & paste, for your convenience)
|
|
||||||
// *** Take care : If Using a board with Microchip 24AA02E64 Uinique ID for deveui, **
|
|
||||||
// *** this DEVEUI will be overwriten by the one contained in the Microchip module ***
|
|
||||||
static const u1_t DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
// Note: Use msb format for APPEUI as in TTN console (cut & paste, for your convenience)
|
static const u1_t APPKEY[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
// For TTN, APPEUI always starts with 0x70, 0xB3, 0xD5
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
static const u1_t APPEUI[8]={ 0x70, 0xB3, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
// Note: Use msb format for APPEUI as in TTN console (cut & paste, for your convenience)
|
|
||||||
static const u1_t APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
*/
|
|
210
src/lorawan.cpp
210
src/lorawan.cpp
@ -7,11 +7,11 @@
|
|||||||
#include <hal/hal.h>
|
#include <hal/hal.h>
|
||||||
|
|
||||||
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||||
#include <Wire.h> // Needed for 24AA02E64, does not hurt anything if included and not used
|
#include <Wire.h> // Needed for 24AA02E64, does not hurt anything if included and not used
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Local logging Tag
|
// Local logging Tag
|
||||||
static const char *TAG = "lorawan";
|
static const char TAG[] = "lora";
|
||||||
|
|
||||||
// functions defined in rcommand.cpp
|
// functions defined in rcommand.cpp
|
||||||
void rcommand(uint8_t cmd, uint8_t arg);
|
void rcommand(uint8_t cmd, uint8_t arg);
|
||||||
@ -29,19 +29,19 @@ void gen_lora_deveui(uint8_t *pdeveui) {
|
|||||||
*p++ = 0xFF;
|
*p++ = 0xFF;
|
||||||
*p++ = 0xFE;
|
*p++ = 0xFE;
|
||||||
// Then next 6 bytes are mac address reversed
|
// Then next 6 bytes are mac address reversed
|
||||||
for ( i=0; i<6 ; i++) {
|
for (i = 0; i < 6; i++) {
|
||||||
*p++ = dmac[5-i];
|
*p++ = dmac[5 - i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to do a byte swap in a byte array
|
// Function to do a byte swap in a byte array
|
||||||
void RevBytes(unsigned char* b, size_t c)
|
void RevBytes(unsigned char *b, size_t c) {
|
||||||
{
|
|
||||||
u1_t i;
|
u1_t i;
|
||||||
for (i = 0; i < c / 2; i++)
|
for (i = 0; i < c / 2; i++) {
|
||||||
{ unsigned char t = b[i];
|
unsigned char t = b[i];
|
||||||
b[i] = b[c - 1 - i];
|
b[i] = b[c - 1 - i];
|
||||||
b[c - 1 - i] = t; }
|
b[c - 1 - i] = t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_hard_deveui(uint8_t *pdeveui) {
|
void get_hard_deveui(uint8_t *pdeveui) {
|
||||||
@ -55,14 +55,14 @@ void get_hard_deveui(uint8_t *pdeveui) {
|
|||||||
i2c_ret = Wire.endTransmission();
|
i2c_ret = Wire.endTransmission();
|
||||||
// check if device seen on i2c bus
|
// check if device seen on i2c bus
|
||||||
if (i2c_ret == 0) {
|
if (i2c_ret == 0) {
|
||||||
char deveui[32]="";
|
char deveui[32] = "";
|
||||||
uint8_t data;
|
uint8_t data;
|
||||||
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
||||||
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
||||||
Wire.requestFrom(MCP_24AA02E64_I2C_ADDRESS, 8);
|
Wire.requestFrom(MCP_24AA02E64_I2C_ADDRESS, 8);
|
||||||
while (Wire.available()) {
|
while (Wire.available()) {
|
||||||
data = Wire.read();
|
data = Wire.read();
|
||||||
sprintf(deveui+strlen(deveui), "%02X ", data);
|
sprintf(deveui + strlen(deveui), "%02X ", data);
|
||||||
*pdeveui++ = data;
|
*pdeveui++ = data;
|
||||||
}
|
}
|
||||||
i2c_ret = Wire.endTransmission();
|
i2c_ret = Wire.endTransmission();
|
||||||
@ -78,14 +78,12 @@ void get_hard_deveui(uint8_t *pdeveui) {
|
|||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
|
|
||||||
// Display a key
|
// Display a key
|
||||||
void printKey(const char * name, const uint8_t * key, uint8_t len, bool lsb) {
|
void printKey(const char *name, const uint8_t *key, uint8_t len, bool lsb) {
|
||||||
uint8_t start=lsb?len:0;
|
const uint8_t *p;
|
||||||
uint8_t end = lsb?0:len;
|
char keystring[len + 1] = "", keybyte[3];
|
||||||
const uint8_t * p ;
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
char keystring[len+1] = "", keybyte[3];
|
p = lsb ? key + len - i - 1 : key + i;
|
||||||
for (uint8_t i=0; i<len ; i++) {
|
sprintf(keybyte, "%02X", *p);
|
||||||
p = lsb ? key+len-i-1 : key+i;
|
|
||||||
sprintf(keybyte, "%02X", * p);
|
|
||||||
strncat(keystring, keybyte, 2);
|
strncat(keystring, keybyte, 2);
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "%s: %s", name, keystring);
|
ESP_LOGI(TAG, "%s: %s", name, keystring);
|
||||||
@ -97,113 +95,170 @@ void printKeys(void) {
|
|||||||
// all EUI buffer so we do it here to a temp
|
// all EUI buffer so we do it here to a temp
|
||||||
// buffer to be able to display them
|
// buffer to be able to display them
|
||||||
uint8_t buf[32];
|
uint8_t buf[32];
|
||||||
os_getDevEui((u1_t*) buf);
|
os_getDevEui((u1_t *)buf);
|
||||||
printKey("DevEUI", buf, 8, true);
|
printKey("DevEUI", buf, 8, true);
|
||||||
os_getArtEui((u1_t*) buf);
|
os_getArtEui((u1_t *)buf);
|
||||||
printKey("AppEUI", buf, 8, true);
|
printKey("AppEUI", buf, 8, true);
|
||||||
os_getDevKey((u1_t*) buf);
|
os_getDevKey((u1_t *)buf);
|
||||||
printKey("AppKey", buf, 16, false);
|
printKey("AppKey", buf, 16, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // VERBOSE
|
#endif // VERBOSE
|
||||||
|
|
||||||
void do_send(osjob_t* j){
|
void do_send(osjob_t *j) {
|
||||||
uint8_t mydata[4];
|
// Schedule next transmission
|
||||||
|
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(cfg.sendcycle * 2),
|
||||||
|
do_send);
|
||||||
|
|
||||||
|
// Check if there is a pending TX/RX job running
|
||||||
|
if (LMIC.opmode & OP_TXRXPEND) {
|
||||||
|
ESP_LOGI(TAG, "LoRa busy, rescheduling");
|
||||||
|
sprintf(display_lmic, "LORA BUSY");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare payload with sum of unique WIFI MACs seen
|
||||||
|
static uint8_t mydata[4];
|
||||||
|
|
||||||
// Sum of unique WIFI MACs seen
|
|
||||||
mydata[0] = (macs_wifi & 0xff00) >> 8;
|
mydata[0] = (macs_wifi & 0xff00) >> 8;
|
||||||
mydata[1] = macs_wifi & 0xff;
|
mydata[1] = macs_wifi & 0xff;
|
||||||
|
|
||||||
#ifdef BLECOUNTER
|
if (cfg.blescan) {
|
||||||
// Sum of unique BLE MACs seen
|
// append sum of unique BLE MACs seen to payload
|
||||||
mydata[2] = (macs_ble & 0xff00) >> 8;
|
mydata[2] = (macs_ble & 0xff00) >> 8;
|
||||||
mydata[3] = macs_ble & 0xff;
|
mydata[3] = macs_ble & 0xff;
|
||||||
#else
|
} else {
|
||||||
mydata[2] = 0;
|
mydata[2] = 0;
|
||||||
mydata[3] = 0;
|
mydata[3] = 0;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
// Check if there is not a current TX/RX job running
|
#ifdef HAS_GPS
|
||||||
if (LMIC.opmode & OP_TXRXPEND) {
|
static uint8_t gpsdata[18];
|
||||||
ESP_LOGI(TAG, "OP_TXRXPEND, not sending");
|
if (cfg.gpsmode && gps.location.isValid()) {
|
||||||
sprintf(display_lmic, "LORA BUSY");
|
gps_read();
|
||||||
|
memcpy(gpsdata, mydata, 4);
|
||||||
|
memcpy(gpsdata + 4, &gps_status, sizeof(gps_status));
|
||||||
|
ESP_LOGI(TAG, "lat=%.6f / lon=%.6f | %u Sats | HDOP=%.1f | Altitude=%u m",
|
||||||
|
gps_status.latitude / (float)1000000,
|
||||||
|
gps_status.longitude / (float)1000000, gps_status.satellites,
|
||||||
|
gps_status.hdop / (float)100, gps_status.altitude);
|
||||||
|
LMIC_setTxData2(COUNTERPORT, gpsdata, sizeof(gpsdata),
|
||||||
|
(cfg.countermode & 0x02));
|
||||||
|
ESP_LOGI(TAG, "%d bytes queued to send", sizeof(gpsdata));
|
||||||
} else {
|
} else {
|
||||||
// Prepare upstream data transmission at the next possible time.
|
#endif
|
||||||
LMIC_setTxData2(1, mydata, sizeof(mydata), (cfg.countermode & 0x02));
|
LMIC_setTxData2(COUNTERPORT, mydata, sizeof(mydata),
|
||||||
ESP_LOGI(TAG, "Packet queued");
|
(cfg.countermode & 0x02));
|
||||||
|
ESP_LOGI(TAG, "%d bytes queued to send", sizeof(mydata));
|
||||||
|
#ifdef HAS_GPS
|
||||||
|
}
|
||||||
|
#endif
|
||||||
sprintf(display_lmic, "PACKET QUEUED");
|
sprintf(display_lmic, "PACKET QUEUED");
|
||||||
|
|
||||||
// clear counter if not in cumulative counter mode
|
// clear counter if not in cumulative counter mode
|
||||||
if (cfg.countermode != 1) {
|
if (cfg.countermode != 1) {
|
||||||
reset_counters(); // clear macs container and reset all counters
|
reset_counters(); // clear macs container and reset all counters
|
||||||
reset_salt(); // get new salt for salting hashes
|
reset_salt(); // get new salt for salting hashes
|
||||||
|
ESP_LOGI(TAG, "Counter cleared (countermode = %d)", cfg.countermode);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Schedule next transmission
|
|
||||||
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(cfg.sendcycle * 2), do_send);
|
|
||||||
|
|
||||||
} // do_send()
|
} // do_send()
|
||||||
|
|
||||||
void onEvent (ev_t ev) {
|
void onEvent(ev_t ev) {
|
||||||
char buff[24]="";
|
char buff[24] = "";
|
||||||
|
|
||||||
switch(ev) {
|
switch (ev) {
|
||||||
case EV_SCAN_TIMEOUT: strcpy_P(buff, PSTR("SCAN TIMEOUT")); break;
|
case EV_SCAN_TIMEOUT:
|
||||||
case EV_BEACON_FOUND: strcpy_P(buff, PSTR("BEACON FOUND")); break;
|
strcpy_P(buff, PSTR("SCAN TIMEOUT"));
|
||||||
case EV_BEACON_MISSED: strcpy_P(buff, PSTR("BEACON MISSED")); break;
|
break;
|
||||||
case EV_BEACON_TRACKED: strcpy_P(buff, PSTR("BEACON TRACKED")); break;
|
case EV_BEACON_FOUND:
|
||||||
case EV_JOINING: strcpy_P(buff, PSTR("JOINING")); break;
|
strcpy_P(buff, PSTR("BEACON FOUND"));
|
||||||
case EV_LOST_TSYNC: strcpy_P(buff, PSTR("LOST TSYNC")); break;
|
break;
|
||||||
case EV_RESET: strcpy_P(buff, PSTR("RESET")); break;
|
case EV_BEACON_MISSED:
|
||||||
case EV_RXCOMPLETE: strcpy_P(buff, PSTR("RX COMPLETE")); break;
|
strcpy_P(buff, PSTR("BEACON MISSED"));
|
||||||
case EV_LINK_DEAD: strcpy_P(buff, PSTR("LINK DEAD")); break;
|
break;
|
||||||
case EV_LINK_ALIVE: strcpy_P(buff, PSTR("LINK ALIVE")); break;
|
case EV_BEACON_TRACKED:
|
||||||
case EV_RFU1: strcpy_P(buff, PSTR("RFUI")); break;
|
strcpy_P(buff, PSTR("BEACON TRACKED"));
|
||||||
case EV_JOIN_FAILED: strcpy_P(buff, PSTR("JOIN FAILED")); break;
|
break;
|
||||||
case EV_REJOIN_FAILED: strcpy_P(buff, PSTR("REJOIN FAILED")); break;
|
case EV_JOINING:
|
||||||
|
strcpy_P(buff, PSTR("JOINING"));
|
||||||
|
break;
|
||||||
|
case EV_LOST_TSYNC:
|
||||||
|
strcpy_P(buff, PSTR("LOST TSYNC"));
|
||||||
|
break;
|
||||||
|
case EV_RESET:
|
||||||
|
strcpy_P(buff, PSTR("RESET"));
|
||||||
|
break;
|
||||||
|
case EV_RXCOMPLETE:
|
||||||
|
strcpy_P(buff, PSTR("RX COMPLETE"));
|
||||||
|
break;
|
||||||
|
case EV_LINK_DEAD:
|
||||||
|
strcpy_P(buff, PSTR("LINK DEAD"));
|
||||||
|
break;
|
||||||
|
case EV_LINK_ALIVE:
|
||||||
|
strcpy_P(buff, PSTR("LINK ALIVE"));
|
||||||
|
break;
|
||||||
|
case EV_RFU1:
|
||||||
|
strcpy_P(buff, PSTR("RFUI"));
|
||||||
|
break;
|
||||||
|
case EV_JOIN_FAILED:
|
||||||
|
strcpy_P(buff, PSTR("JOIN FAILED"));
|
||||||
|
break;
|
||||||
|
case EV_REJOIN_FAILED:
|
||||||
|
strcpy_P(buff, PSTR("REJOIN FAILED"));
|
||||||
|
break;
|
||||||
|
|
||||||
case EV_JOINED:
|
case EV_JOINED:
|
||||||
|
|
||||||
joinstate=true;
|
|
||||||
strcpy_P(buff, PSTR("JOINED"));
|
strcpy_P(buff, PSTR("JOINED"));
|
||||||
|
sprintf(display_lora, " "); // clear previous lmic status
|
||||||
|
|
||||||
// Disable link check validation (automatically enabled
|
|
||||||
// during join, but not supported by TTN at this time).
|
|
||||||
LMIC_setLinkCheckMode(0);
|
|
||||||
// set data rate adaptation
|
// set data rate adaptation
|
||||||
LMIC_setAdrMode(cfg.adrmode);
|
LMIC_setAdrMode(cfg.adrmode);
|
||||||
// Set data rate and transmit power (note: txpower seems to be ignored by the library)
|
// Set data rate and transmit power (note: txpower seems to be ignored by
|
||||||
switch_lora(cfg.lorasf,cfg.txpower);
|
// the library)
|
||||||
|
switch_lora(cfg.lorasf, cfg.txpower);
|
||||||
|
|
||||||
// show effective LoRa parameters after join
|
// show effective LoRa parameters after join
|
||||||
ESP_LOGI(TAG, "ADR=%d, SF=%d, TXPOWER=%d", cfg.adrmode, cfg.lorasf, cfg.txpower);
|
ESP_LOGI(TAG, "ADR=%d, SF=%d, TXPOWER=%d", cfg.adrmode, cfg.lorasf,
|
||||||
|
cfg.txpower);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_TXCOMPLETE:
|
case EV_TXCOMPLETE:
|
||||||
|
|
||||||
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK") : PSTR("TX COMPLETE"));
|
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK")
|
||||||
sprintf(display_lora, ""); // erase previous LoRa message from display
|
: PSTR("TX COMPLETE"));
|
||||||
|
sprintf(display_lora, " "); // clear previous lmic status
|
||||||
|
|
||||||
if (LMIC.dataLen) {
|
if (LMIC.dataLen) {
|
||||||
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d", LMIC.dataLen, LMIC.rssi, (signed char)LMIC.snr / 4);
|
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.snr = SNR twos compliment [dB] * 4
|
||||||
// LMIC.rssi = RSSI [dBm] (-196...+63)
|
// LMIC.rssi = RSSI [dBm] (-196...+63)
|
||||||
sprintf(display_lora, "RSSI %d SNR %d", LMIC.rssi, (signed char)LMIC.snr / 4 );
|
sprintf(display_lora, "RSSI %d SNR %d", LMIC.rssi,
|
||||||
|
(signed char)LMIC.snr / 4);
|
||||||
|
|
||||||
// check if payload received on command port, then call remote command interpreter
|
// check if payload received on command port, then call remote command
|
||||||
if ( (LMIC.txrxFlags & TXRX_PORT) && (LMIC.frame[LMIC.dataBeg-1] == RCMDPORT ) ) {
|
// interpreter
|
||||||
// caution: buffering LMIC values here because rcommand() can modify LMIC.frame
|
if ((LMIC.txrxFlags & TXRX_PORT) &&
|
||||||
unsigned char* buffer = new unsigned char[MAX_LEN_FRAME];
|
(LMIC.frame[LMIC.dataBeg - 1] == RCMDPORT)) {
|
||||||
memcpy(buffer, LMIC.frame, MAX_LEN_FRAME); //Copy data from cfg to char*
|
// caution: buffering LMIC values here because rcommand() can modify
|
||||||
int i, k = LMIC.dataBeg, l = LMIC.dataBeg+LMIC.dataLen-2;
|
// LMIC.frame
|
||||||
for (i=k; i<=l; i+=2)
|
unsigned char *buffer = new unsigned char[MAX_LEN_FRAME];
|
||||||
rcommand(buffer[i], buffer[i+1]);
|
memcpy(buffer, LMIC.frame, MAX_LEN_FRAME); // Copy data from cfg to
|
||||||
delete[] buffer; //free memory
|
// char*
|
||||||
|
int i, k = LMIC.dataBeg, l = LMIC.dataBeg + LMIC.dataLen - 2;
|
||||||
|
for (i = k; i <= l; i += 2) {
|
||||||
|
rcommand(buffer[i], buffer[i + 1]);
|
||||||
|
}
|
||||||
|
delete[] buffer; // free memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: sprintf_P(buff, PSTR("UNKNOWN EVENT %d"), ev); break;
|
default:
|
||||||
|
sprintf_P(buff, PSTR("UNKNOWN EVENT %d"), ev);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log & Display if asked
|
// Log & Display if asked
|
||||||
@ -213,4 +268,3 @@ void onEvent (ev_t ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // onEvent()
|
} // onEvent()
|
||||||
|
|
||||||
|
10
src/lorawan.h
Normal file
10
src/lorawan.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef LORAWAN_H
|
||||||
|
#define LORAWAN_H
|
||||||
|
|
||||||
|
void onEvent(ev_t ev);
|
||||||
|
void do_send(osjob_t *j);
|
||||||
|
void gen_lora_deveui(uint8_t *pdeveui);
|
||||||
|
void RevBytes(unsigned char *b, size_t c);
|
||||||
|
void get_hard_deveui(uint8_t *pdeveui);
|
||||||
|
|
||||||
|
#endif
|
109
src/macsniff.cpp
109
src/macsniff.cpp
@ -3,21 +3,22 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
#ifdef VENDORFILTER
|
#ifdef VENDORFILTER
|
||||||
#include <array>
|
#include "vendor_array.h"
|
||||||
#include <algorithm>
|
|
||||||
#include "vendor_array.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char *TAG = "macsniff";
|
static const char TAG[] = "wifi";
|
||||||
|
|
||||||
static wifi_country_t wifi_country = {.cc=WIFI_MY_COUNTRY, .schan=WIFI_CHANNEL_MIN, .nchan=WIFI_CHANNEL_MAX, .policy=WIFI_COUNTRY_POLICY_MANUAL};
|
static wifi_country_t wifi_country = {.cc = WIFI_MY_COUNTRY,
|
||||||
|
.schan = WIFI_CHANNEL_MIN,
|
||||||
|
.nchan = WIFI_CHANNEL_MAX,
|
||||||
|
.policy = WIFI_COUNTRY_POLICY_MANUAL};
|
||||||
|
|
||||||
// globals
|
// globals
|
||||||
uint16_t salt;
|
uint16_t salt;
|
||||||
|
|
||||||
uint16_t reset_salt(void) {
|
uint16_t reset_salt(void) {
|
||||||
salt = random(65536); // get new 16bit random for salting hashes and set global salt var
|
salt = random(65536); // get new 16bit random for salting hashes
|
||||||
return salt;
|
return salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,70 +31,84 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) {
|
|||||||
|
|
||||||
// only last 3 MAC Address bytes are used for MAC address anonymization
|
// only last 3 MAC Address bytes are used for MAC address anonymization
|
||||||
// but since it's uint32 we take 4 bytes to avoid 1st value to be 0
|
// but since it's uint32 we take 4 bytes to avoid 1st value to be 0
|
||||||
addr2int = ( (uint32_t)paddr[2] ) | ( (uint32_t)paddr[3] << 8 ) | ( (uint32_t)paddr[4] << 16 ) | ( (uint32_t)paddr[5] << 24 );
|
addr2int = ((uint32_t)paddr[2]) | ((uint32_t)paddr[3] << 8) |
|
||||||
|
((uint32_t)paddr[4] << 16) | ((uint32_t)paddr[5] << 24);
|
||||||
|
|
||||||
#ifdef VENDORFILTER
|
#ifdef VENDORFILTER
|
||||||
vendor2int = ( (uint32_t)paddr[2] ) | ( (uint32_t)paddr[1] << 8 ) | ( (uint32_t)paddr[0] << 16 );
|
vendor2int = ((uint32_t)paddr[2]) | ((uint32_t)paddr[1] << 8) |
|
||||||
|
((uint32_t)paddr[0] << 16);
|
||||||
// use OUI vendor filter list only on Wifi, not on BLE
|
// use OUI vendor filter list only on Wifi, not on BLE
|
||||||
if ( (sniff_type==MAC_SNIFF_BLE) || std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end() )
|
if ((sniff_type == MAC_SNIFF_BLE) ||
|
||||||
{
|
std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end()) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// salt and hash MAC, and if new unique one, store identifier in container and increment counter on display
|
// salt and hash MAC, and if new unique one, store identifier in container
|
||||||
|
// and increment counter on display
|
||||||
// https://en.wikipedia.org/wiki/MAC_Address_Anonymization
|
// https://en.wikipedia.org/wiki/MAC_Address_Anonymization
|
||||||
|
|
||||||
addr2int += (uint32_t)salt; // add 16-bit salt to pseudo MAC
|
addr2int += (uint32_t)salt; // add 16-bit salt to pseudo MAC
|
||||||
snprintf(buff, sizeof(buff), "%08X", addr2int); // convert unsigned 32-bit salted MAC to 8 digit hex string
|
snprintf(
|
||||||
hashedmac = rokkit(&buff[3], 5); // hash MAC last string value, use 5 chars to fit hash in uint16_t container
|
buff, sizeof(buff), "%08X",
|
||||||
auto newmac = macs.insert(hashedmac); // add hashed MAC to total container if new unique
|
addr2int); // convert unsigned 32-bit salted MAC to 8 digit hex string
|
||||||
added = newmac.second ? true:false; // true if hashed MAC is unique in container
|
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
|
||||||
|
added = newmac.second ? true
|
||||||
|
: false; // true if hashed MAC is unique in container
|
||||||
|
|
||||||
// Count only if MAC was not yet seen
|
// Count only if MAC was not yet seen
|
||||||
if (added) {
|
if (added) {
|
||||||
// increment counter and one blink led
|
// increment counter and one blink led
|
||||||
if (sniff_type == MAC_SNIFF_WIFI ) {
|
if (sniff_type == MAC_SNIFF_WIFI) {
|
||||||
macs_wifi++; // increment Wifi MACs counter
|
macs_wifi++; // increment Wifi MACs counter
|
||||||
#if (HAS_LED != NOT_A_PIN) || defined (HAS_RGB_LED)
|
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||||
blink_LED(COLOR_GREEN, 50);
|
blink_LED(COLOR_GREEN, 50);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef BLECOUNTER
|
#ifdef BLECOUNTER
|
||||||
else if (sniff_type == MAC_SNIFF_BLE ) {
|
else if (sniff_type == MAC_SNIFF_BLE) {
|
||||||
macs_ble++; // increment BLE Macs counter
|
macs_ble++; // increment BLE Macs counter
|
||||||
#if (HAS_LED != NOT_A_PIN) || defined (HAS_RGB_LED)
|
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||||
blink_LED(COLOR_MAGENTA, 50);
|
blink_LED(COLOR_MAGENTA, 50);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log scan result
|
// Log scan result
|
||||||
ESP_LOGI(TAG, "%s %s RSSI %ddBi -> MAC %s -> Hash %04X -> WiFi:%d BLTH:%d -> %d Bytes left",
|
ESP_LOGI(TAG,
|
||||||
|
"%s %s RSSI %ddBi -> MAC %s -> Hash %04X -> WiFi:%d BLTH:%d -> "
|
||||||
|
"%d Bytes left",
|
||||||
added ? "new " : "known",
|
added ? "new " : "known",
|
||||||
sniff_type==MAC_SNIFF_WIFI ? "WiFi":"BLTH",
|
sniff_type == MAC_SNIFF_WIFI ? "WiFi" : "BLTH", rssi, buff,
|
||||||
rssi, buff, hashedmac, macs_wifi, macs_ble,
|
hashedmac, macs_wifi, macs_ble, ESP.getFreeHeap());
|
||||||
ESP.getFreeHeap());
|
|
||||||
|
|
||||||
#ifdef VENDORFILTER
|
#ifdef VENDORFILTER
|
||||||
} else {
|
} else {
|
||||||
// Very noisy
|
// Very noisy
|
||||||
// ESP_LOGD(TAG, "Filtered MAC %02X:%02X:%02X:%02X:%02X:%02X", paddr[0],paddr[1],paddr[2],paddr[3],paddr[5],paddr[5]);
|
// ESP_LOGD(TAG, "Filtered MAC %02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
// paddr[0],paddr[1],paddr[2],paddr[3],paddr[5],paddr[5]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// True if MAC WiFi/BLE was new
|
// True if MAC WiFi/BLE was new
|
||||||
return added; // function returns bool if a new and unique Wifi or BLE mac was counted (true) or not (false)
|
return added; // function returns bool if a new and unique Wifi or BLE mac was
|
||||||
|
// counted (true) or not (false)
|
||||||
}
|
}
|
||||||
|
|
||||||
void wifi_sniffer_init(void) {
|
void wifi_sniffer_init(void) {
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
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
|
||||||
wifi_promiscuous_filter_t filter = {.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames
|
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
|
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_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM
|
esp_wifi_set_country(&wifi_country)); // set locales for RF and channels
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
|
ESP_ERROR_CHECK(
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
|
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_set_promiscuous_filter(&filter)); // set MAC frame filter
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
|
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); // now switch on monitor mode
|
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); // now switch on monitor mode
|
||||||
}
|
}
|
||||||
@ -102,16 +117,20 @@ void wifi_sniffer_set_channel(uint8_t channel) {
|
|||||||
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
|
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wifi_sniffer_packet_handler(void* buff, wifi_promiscuous_pkt_type_t type) {
|
// using IRAM_:ATTR here to speed up callback function
|
||||||
|
IRAM_ATTR void wifi_sniffer_packet_handler(void *buff,
|
||||||
|
wifi_promiscuous_pkt_type_t type) {
|
||||||
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
|
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
|
||||||
const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)ppkt->payload;
|
const wifi_ieee80211_packet_t *ipkt =
|
||||||
|
(wifi_ieee80211_packet_t *)ppkt->payload;
|
||||||
const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr;
|
const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr;
|
||||||
|
|
||||||
if (( cfg.rssilimit == 0 ) || (ppkt->rx_ctrl.rssi > cfg.rssilimit )) { // rssi is negative value
|
if ((cfg.rssilimit) &&
|
||||||
uint8_t *p = (uint8_t *) hdr->addr2;
|
(ppkt->rx_ctrl.rssi < cfg.rssilimit)) { // rssi is negative value
|
||||||
mac_add(p, ppkt->rx_ctrl.rssi, MAC_SNIFF_WIFI) ;
|
ESP_LOGI(TAG, "WiFi RSSI %d -> ignoring (limit: %d)", ppkt->rx_ctrl.rssi,
|
||||||
|
cfg.rssilimit);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG, "WiFi RSSI %d -> ignoring (limit: %d)", ppkt->rx_ctrl.rssi, cfg.rssilimit);
|
uint8_t *p = (uint8_t *)hdr->addr2;
|
||||||
|
mac_add(p, ppkt->rx_ctrl.rssi, MAC_SNIFF_WIFI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
#ifndef MACSNIFF_H
|
||||||
|
#define MACSNIFF_H
|
||||||
|
|
||||||
// ESP32 Functions
|
// ESP32 Functions
|
||||||
#include <esp_wifi.h>
|
#include <esp_wifi.h>
|
||||||
|
|
||||||
@ -5,12 +8,12 @@
|
|||||||
#define MAC_SNIFF_BLE 1
|
#define MAC_SNIFF_BLE 1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned frame_ctrl:16;
|
unsigned frame_ctrl : 16;
|
||||||
unsigned duration_id:16;
|
unsigned duration_id : 16;
|
||||||
uint8_t addr1[6]; /* receiver address */
|
uint8_t addr1[6]; /* receiver address */
|
||||||
uint8_t addr2[6]; /* sender address */
|
uint8_t addr2[6]; /* sender address */
|
||||||
uint8_t addr3[6]; /* filtering address */
|
uint8_t addr3[6]; /* filtering address */
|
||||||
unsigned sequence_ctrl:16;
|
unsigned sequence_ctrl : 16;
|
||||||
uint8_t addr4[6]; /* optional */
|
uint8_t addr4[6]; /* optional */
|
||||||
} wifi_ieee80211_mac_hdr_t;
|
} wifi_ieee80211_mac_hdr_t;
|
||||||
|
|
||||||
@ -25,4 +28,6 @@ void wifi_sniffer_set_channel(uint8_t channel);
|
|||||||
void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
||||||
|
|
||||||
// function defined in rokkithash.cpp
|
// function defined in rokkithash.cpp
|
||||||
uint32_t rokkit(const char * , int );
|
uint32_t rokkit(const char *, int);
|
||||||
|
|
||||||
|
#endif
|
510
src/main.cpp
510
src/main.cpp
@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
ESP32-Paxcounter
|
||||||
|
|
||||||
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
|
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
|
||||||
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
|
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
|
||||||
@ -16,8 +17,8 @@ Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
NOTICE:
|
NOTICE:
|
||||||
Parts of the source files in this repository are made available under different licenses.
|
Parts of the source files in this repository are made available under different
|
||||||
Refer to LICENSE.txt file in repository for more details.
|
licenses. Refer to LICENSE.txt file in repository for more details.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -29,47 +30,58 @@ Refer to LICENSE.txt file in repository for more details.
|
|||||||
|
|
||||||
// LMIC-Arduino LoRaWAN Stack
|
// LMIC-Arduino LoRaWAN Stack
|
||||||
#include "loraconf.h"
|
#include "loraconf.h"
|
||||||
#include <lmic.h>
|
|
||||||
#include <hal/hal.h>
|
#include <hal/hal.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
|
||||||
// ESP32 lib Functions
|
// ESP32 lib Functions
|
||||||
|
#include <esp32-hal-log.h> // needed for ESP_LOGx on arduino framework
|
||||||
#include <esp_event_loop.h> // needed for Wifi event handler
|
#include <esp_event_loop.h> // needed for Wifi event handler
|
||||||
#include <esp_spi_flash.h> // needed for reading ESP32 chip attributes
|
#include <esp_spi_flash.h> // needed for reading ESP32 chip attributes
|
||||||
#include <esp32-hal-log.h> // needed for ESP_LOGx on arduino framework
|
|
||||||
|
|
||||||
// Initialize global variables
|
// Initialize global variables
|
||||||
configData_t cfg; // struct holds current device configuration
|
configData_t cfg; // struct holds current device configuration
|
||||||
osjob_t sendjob, initjob; // LMIC jobs
|
osjob_t sendjob, rcmdjob; // LMIC job handler
|
||||||
uint64_t uptimecounter = 0; // timer global for uptime counter
|
uint64_t uptimecounter = 0; // timer global for uptime counter
|
||||||
uint8_t DisplayState = 0; // globals for state machine
|
uint8_t DisplayState = 0; // globals for state machine
|
||||||
uint16_t macs_total = 0, macs_wifi = 0, macs_ble = 0; // MAC counters globals for display
|
uint16_t macs_total = 0, macs_wifi = 0,
|
||||||
|
macs_ble = 0; // MAC counters globals for display
|
||||||
uint8_t channel = 0; // wifi channel rotation counter global for display
|
uint8_t channel = 0; // wifi channel rotation counter global for display
|
||||||
char display_lora[16], display_lmic[16]; // display buffers
|
char display_lora[16], display_lmic[16]; // display buffers
|
||||||
led_states LEDState = LED_OFF; // LED state global for state machine
|
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
|
led_states previousLEDState =
|
||||||
|
LED_ON; // This will force LED to be off at boot since State is OFF
|
||||||
unsigned long LEDBlinkStarted = 0; // When (in millis() led blink started)
|
unsigned long LEDBlinkStarted = 0; // When (in millis() led blink started)
|
||||||
uint16_t LEDBlinkDuration = 0; // How long the blink need to be
|
uint16_t LEDBlinkDuration = 0; // How long the blink need to be
|
||||||
uint16_t LEDColor = COLOR_NONE; // state machine variable to set RGB LED color
|
uint16_t LEDColor = COLOR_NONE; // state machine variable to set RGB LED color
|
||||||
bool joinstate = false; // LoRa network joined? global flag
|
hw_timer_t *displaytimer =
|
||||||
bool blinkdone = true; // flag for state machine for blinking LED once
|
NULL; // configure hardware timer used for cyclic display refresh
|
||||||
hw_timer_t * displaytimer = NULL; // configure hardware timer used for cyclic display refresh
|
hw_timer_t *channelSwitch =
|
||||||
hw_timer_t * channelSwitch = NULL; // configure hardware timer used for wifi channel switching
|
NULL; // configure hardware timer used for wifi channel switching
|
||||||
|
xref2u1_t rcmd_data; // buffer for rcommand results size
|
||||||
|
u1_t rcmd_data_size; // buffer for rcommand results size
|
||||||
|
|
||||||
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; // sync main loop and ISR when modifying shared variable DisplayIRQ
|
#ifdef HAS_GPS
|
||||||
|
gpsStatus_t gps_status; // struct for storing gps data
|
||||||
|
TinyGPSPlus gps; // create TinyGPS++ instance
|
||||||
|
#endif
|
||||||
|
|
||||||
std::set<uint16_t> macs; // associative container holds total of unique MAC adress hashes (Wifi + BLE)
|
portMUX_TYPE timerMux =
|
||||||
|
portMUX_INITIALIZER_UNLOCKED; // sync main loop and ISR when modifying IRQ
|
||||||
|
// handler shared variables
|
||||||
|
|
||||||
|
std::set<uint16_t> macs; // associative container holds total of unique MAC
|
||||||
|
// adress hashes (Wifi + BLE)
|
||||||
|
|
||||||
// this variables will be changed in the ISR, and read in main loop
|
// this variables will be changed in the ISR, and read in main loop
|
||||||
static volatile int ButtonPressed = 0, DisplayTimerIRQ = 0, ChannelTimerIRQ = 0;
|
static volatile int ButtonPressedIRQ = 0, DisplayTimerIRQ = 0,
|
||||||
|
ChannelTimerIRQ = 0;
|
||||||
|
|
||||||
// local Tag for logging
|
// local Tag for logging
|
||||||
static const char *TAG = "paxcnt";
|
static const char TAG[] = "main";
|
||||||
// Note: Log level control seems not working during runtime,
|
|
||||||
// so we need to switch loglevel by compiler build option in platformio.ini
|
|
||||||
|
|
||||||
#ifndef VERBOSE
|
#ifndef VERBOSE
|
||||||
int redirect_log(const char * fmt, va_list args) {
|
int redirect_log(const char *fmt, va_list args) {
|
||||||
//do nothing
|
// do nothing
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -81,27 +93,25 @@ void reset_counters() {
|
|||||||
macs_ble = 0;
|
macs_ble = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* begin LMIC specific parts ------------------------------------------------------------ */
|
/* begin LMIC specific parts
|
||||||
|
* ------------------------------------------------------------ */
|
||||||
|
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
void printKeys(void);
|
void printKeys(void);
|
||||||
#endif // VERBOSE
|
#endif // VERBOSE
|
||||||
|
|
||||||
// LMIC callback functions
|
// LMIC callback functions
|
||||||
void os_getDevKey (u1_t *buf) {
|
void os_getDevKey(u1_t *buf) { memcpy(buf, APPKEY, 16); }
|
||||||
memcpy(buf, APPKEY, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void os_getArtEui (u1_t *buf) {
|
void os_getArtEui(u1_t *buf) {
|
||||||
memcpy(buf, APPEUI, 8);
|
memcpy(buf, APPEUI, 8);
|
||||||
RevBytes(buf, 8); // TTN requires it in LSB First order, so we swap bytes
|
RevBytes(buf, 8); // TTN requires it in LSB First order, so we swap bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
void os_getDevEui (u1_t* buf) {
|
void os_getDevEui(u1_t *buf) {
|
||||||
int i=0, k=0;
|
int i = 0, k = 0;
|
||||||
memcpy(buf, DEVEUI, 8); // get fixed DEVEUI from loraconf.h
|
memcpy(buf, DEVEUI, 8); // get fixed DEVEUI from loraconf.h
|
||||||
for (i=0; i<8 ; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
k += buf[i];
|
k += buf[i];
|
||||||
}
|
}
|
||||||
if (k) {
|
if (k) {
|
||||||
@ -110,118 +120,82 @@ void os_getDevEui (u1_t* buf) {
|
|||||||
gen_lora_deveui(buf); // generate DEVEUI from device's MAC
|
gen_lora_deveui(buf); // generate DEVEUI from device's MAC
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get MCP 24AA02E64 hardware DEVEUI (override default settings if found)
|
// Get MCP 24AA02E64 hardware DEVEUI (override default settings if found)
|
||||||
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||||
get_hard_deveui(buf);
|
get_hard_deveui(buf);
|
||||||
RevBytes(buf, 8); // swap bytes to LSB format
|
RevBytes(buf, 8); // swap bytes to LSB format
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// LMIC enhanced Pin mapping
|
// LMIC enhanced Pin mapping
|
||||||
const lmic_pinmap lmic_pins = {
|
const lmic_pinmap lmic_pins = {.mosi = PIN_SPI_MOSI,
|
||||||
.mosi = PIN_SPI_MOSI,
|
|
||||||
.miso = PIN_SPI_MISO,
|
.miso = PIN_SPI_MISO,
|
||||||
.sck = PIN_SPI_SCK,
|
.sck = PIN_SPI_SCK,
|
||||||
.nss = PIN_SPI_SS,
|
.nss = PIN_SPI_SS,
|
||||||
.rxtx = LMIC_UNUSED_PIN,
|
.rxtx = LMIC_UNUSED_PIN,
|
||||||
.rst = RST,
|
.rst = RST,
|
||||||
.dio = {DIO0, DIO1, DIO2}
|
.dio = {DIO0, DIO1, DIO2}};
|
||||||
};
|
|
||||||
|
|
||||||
// LoRaWAN Initjob
|
|
||||||
static void lora_init (osjob_t* j) {
|
|
||||||
// reset 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);
|
|
||||||
// start joining
|
|
||||||
LMIC_startJoining();
|
|
||||||
}
|
|
||||||
|
|
||||||
// LMIC FreeRTos Task
|
// LMIC FreeRTos Task
|
||||||
void lorawan_loop(void * pvParameters) {
|
void lorawan_loop(void *pvParameters) {
|
||||||
|
|
||||||
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
|
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||||
|
|
||||||
static uint16_t lorawait = 0;
|
while (1) {
|
||||||
|
os_runloop_once(); // execute LMIC jobs
|
||||||
while(1) {
|
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||||
|
|
||||||
// execute LMIC jobs
|
|
||||||
os_runloop_once();
|
|
||||||
|
|
||||||
// indicate LMIC state on LEDs if present
|
|
||||||
#if (HAS_LED != NOT_A_PIN) || defined (HAS_RGB_LED)
|
|
||||||
led_loop();
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
// check if payload is sent
|
|
||||||
while(LMIC.opmode & OP_TXRXPEND) {
|
|
||||||
if(!lorawait)
|
|
||||||
sprintf(display_lora, "LoRa wait");
|
|
||||||
lorawait++;
|
|
||||||
// in case sending really fails: reset LMIC and rejoin network
|
|
||||||
if( (lorawait % MAXLORARETRY ) == 0) {
|
|
||||||
ESP_LOGI(TAG, "Payload not sent, resetting LMIC and rejoin");
|
|
||||||
lorawait = 0;
|
|
||||||
LMIC_reset(); // Reset the MAC state. Session and pending data transfers will be discarded.
|
|
||||||
};
|
|
||||||
vTaskDelay(1000/portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
vTaskDelay(10/portTICK_PERIOD_MS); // reset watchdog
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end LMIC specific parts --------------------------------------------------------------- */
|
/* end LMIC specific parts
|
||||||
|
* --------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* beginn hardware specific parts
|
||||||
|
* -------------------------------------------------------- */
|
||||||
/* beginn hardware specific parts -------------------------------------------------------- */
|
|
||||||
|
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
HAS_DISPLAY u8x8(OLED_RST, OLED_SCL, OLED_SDA);
|
HAS_DISPLAY u8x8(OLED_RST, OLED_SCL, OLED_SDA);
|
||||||
// Display Refresh IRQ
|
// Display Refresh IRQ
|
||||||
void IRAM_ATTR DisplayIRQ() {
|
void IRAM_ATTR DisplayIRQ() {
|
||||||
portENTER_CRITICAL_ISR(&timerMux);
|
portENTER_CRITICAL_ISR(&timerMux);
|
||||||
DisplayTimerIRQ++;
|
DisplayTimerIRQ++;
|
||||||
portEXIT_CRITICAL_ISR(&timerMux);
|
portEXIT_CRITICAL_ISR(&timerMux);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_ANTENNA_SWITCH
|
#ifdef HAS_ANTENNA_SWITCH
|
||||||
// defined in antenna.cpp
|
// defined in antenna.cpp
|
||||||
void antenna_init();
|
void antenna_init();
|
||||||
void antenna_select(const uint8_t _ant);
|
void antenna_select(const uint8_t _ant);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BLECOUNTER
|
#ifndef BLECOUNTER
|
||||||
bool btstop = btStop();
|
bool btstop = btStop();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Button IRQ Handler Routine, IRAM_ATTR necessary here, see
|
||||||
|
// https://github.com/espressif/arduino-esp32/issues/855
|
||||||
#ifdef HAS_BUTTON
|
#ifdef HAS_BUTTON
|
||||||
// Button IRQ
|
void IRAM_ATTR ButtonIRQ() { ButtonPressedIRQ++; }
|
||||||
// IRAM_ATTR necessary here, see https://github.com/espressif/arduino-esp32/issues/855
|
|
||||||
void IRAM_ATTR ButtonIRQ() {
|
|
||||||
ButtonPressed++;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Wifi Channel Rotation Timer IRQ Handler Routine
|
||||||
void IRAM_ATTR ChannelSwitchIRQ() {
|
void IRAM_ATTR ChannelSwitchIRQ() {
|
||||||
portENTER_CRITICAL(&timerMux);
|
portENTER_CRITICAL(&timerMux);
|
||||||
ChannelTimerIRQ++;
|
ChannelTimerIRQ++;
|
||||||
portEXIT_CRITICAL(&timerMux);
|
portEXIT_CRITICAL(&timerMux);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end hardware specific parts -------------------------------------------------------- */
|
/* end hardware specific parts
|
||||||
|
* -------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* begin wifi specific parts
|
||||||
/* begin wifi specific parts ---------------------------------------------------------- */
|
* ---------------------------------------------------------- */
|
||||||
|
|
||||||
// Sniffer Task
|
// Sniffer Task
|
||||||
void sniffer_loop(void * pvParameters) {
|
void sniffer_loop(void *pvParameters) {
|
||||||
|
|
||||||
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
|
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
@ -234,38 +208,38 @@ void sniffer_loop(void * pvParameters) {
|
|||||||
wifi_sniffer_set_channel(channel);
|
wifi_sniffer_set_channel(channel);
|
||||||
ESP_LOGD(TAG, "Wifi set channel %d", channel);
|
ESP_LOGD(TAG, "Wifi set channel %d", channel);
|
||||||
|
|
||||||
vTaskDelay(10/portTICK_PERIOD_MS); // reset watchdog
|
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of infinite wifi channel rotation loop
|
} // end of infinite wifi channel rotation loop
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end wifi specific parts ------------------------------------------------------------ */
|
/* end wifi specific parts
|
||||||
|
* ------------------------------------------------------------ */
|
||||||
|
|
||||||
// uptime counter 64bit to prevent millis() rollover after 49 days
|
// uptime counter 64bit to prevent millis() rollover after 49 days
|
||||||
uint64_t uptime() {
|
uint64_t uptime() {
|
||||||
static uint32_t low32, high32;
|
static uint32_t low32, high32;
|
||||||
uint32_t new_low32 = millis();
|
uint32_t new_low32 = millis();
|
||||||
if (new_low32 < low32) high32++;
|
if (new_low32 < low32)
|
||||||
|
high32++;
|
||||||
low32 = new_low32;
|
low32 = new_low32;
|
||||||
return (uint64_t) high32 << 32 | low32;
|
return (uint64_t)high32 << 32 | low32;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
|
|
||||||
// Print a key on display
|
// Print a key on display
|
||||||
void DisplayKey(const uint8_t * key, uint8_t len, bool lsb) {
|
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) {
|
||||||
uint8_t start=lsb?len:0;
|
const uint8_t *p;
|
||||||
uint8_t end = lsb?0:len;
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
const uint8_t * p ;
|
p = lsb ? key + len - i - 1 : key + i;
|
||||||
for (uint8_t i=0; i<len ; i++) {
|
|
||||||
p = lsb ? key+len-i-1 : key+i;
|
|
||||||
u8x8.printf("%02X", *p);
|
u8x8.printf("%02X", *p);
|
||||||
}
|
}
|
||||||
u8x8.printf("\n");
|
u8x8.printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_display(const char *Productname, const char *Version) {
|
void init_display(const char *Productname, const char *Version) {
|
||||||
uint8_t buf[32];
|
uint8_t buf[32];
|
||||||
u8x8.begin();
|
u8x8.begin();
|
||||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||||
@ -287,73 +261,92 @@ uint64_t uptime() {
|
|||||||
u8x8.setFlipMode(0);
|
u8x8.setFlipMode(0);
|
||||||
u8x8.clear();
|
u8x8.clear();
|
||||||
|
|
||||||
#ifdef DISPLAY_FLIP
|
#ifdef DISPLAY_FLIP
|
||||||
u8x8.setFlipMode(1);
|
u8x8.setFlipMode(1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Display chip information
|
// Display chip information
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
esp_chip_info_t chip_info;
|
esp_chip_info_t chip_info;
|
||||||
esp_chip_info(&chip_info);
|
esp_chip_info(&chip_info);
|
||||||
u8x8.printf("ESP32 %d cores\nWiFi%s%s\n",
|
u8x8.printf("ESP32 %d cores\nWiFi%s%s\n", chip_info.cores,
|
||||||
chip_info.cores,
|
|
||||||
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
||||||
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
|
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
|
||||||
u8x8.printf("ESP Rev.%d\n", chip_info.revision);
|
u8x8.printf("ESP Rev.%d\n", chip_info.revision);
|
||||||
u8x8.printf("%dMB %s Flash\n", spi_flash_get_chip_size() / (1024 * 1024),
|
u8x8.printf("%dMB %s Flash\n", spi_flash_get_chip_size() / (1024 * 1024),
|
||||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext.");
|
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext.");
|
||||||
#endif // VERBOSE
|
#endif // VERBOSE
|
||||||
|
|
||||||
u8x8.print(Productname);
|
u8x8.print(Productname);
|
||||||
u8x8.print(" v");
|
u8x8.print(" v");
|
||||||
u8x8.println(PROGVERSION);
|
u8x8.println(PROGVERSION);
|
||||||
u8x8.println("DEVEUI:");
|
u8x8.println("DEVEUI:");
|
||||||
os_getDevEui((u1_t*) buf);
|
os_getDevEui((u1_t *)buf);
|
||||||
DisplayKey(buf, 8, true);
|
DisplayKey(buf, 8, true);
|
||||||
delay(5000);
|
delay(5000);
|
||||||
u8x8.clear();
|
u8x8.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshDisplay() {
|
void refreshDisplay() {
|
||||||
// update counter display (lines 0-4)
|
// update counter (lines 0-1)
|
||||||
char buff[16];
|
char buff[16];
|
||||||
snprintf(buff, sizeof(buff), "PAX:%-4d", (int) macs.size()); // convert 16-bit MAC counter to decimal counter value
|
snprintf(
|
||||||
u8x8.draw2x2String(0, 0, buff); // display number on unique macs total Wifi + BLE
|
buff, sizeof(buff), "PAX:%-4d",
|
||||||
u8x8.setCursor(0,4);
|
(int)macs.size()); // convert 16-bit MAC counter to decimal counter value
|
||||||
u8x8.printf("WIFI:%-4d", macs_wifi);
|
u8x8.draw2x2String(0, 0,
|
||||||
|
buff); // display number on unique macs total Wifi + BLE
|
||||||
|
|
||||||
#ifdef BLECOUNTER
|
// update GPS status (line 2)
|
||||||
u8x8.setCursor(0,3);
|
#ifdef HAS_GPS
|
||||||
|
u8x8.setCursor(7, 2);
|
||||||
|
if (!gps.location.isValid()) // if no fix then display Sats value inverse
|
||||||
|
{
|
||||||
|
u8x8.setInverseFont(1);
|
||||||
|
u8x8.printf("Sats: %.3d", gps.satellites.value());
|
||||||
|
u8x8.setInverseFont(0);
|
||||||
|
} else
|
||||||
|
u8x8.printf("Sats: %.3d", gps.satellites.value());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// update bluetooth counter + LoRa SF (line 3)
|
||||||
|
#ifdef BLECOUNTER
|
||||||
|
u8x8.setCursor(0, 3);
|
||||||
if (cfg.blescan)
|
if (cfg.blescan)
|
||||||
u8x8.printf("BLTH:%-4d", macs_ble);
|
u8x8.printf("BLTH:%-4d", macs_ble);
|
||||||
else
|
else
|
||||||
u8x8.printf("%-16s", "BLTH:off");
|
u8x8.printf("%s", "BLTH:off");
|
||||||
#endif
|
#endif
|
||||||
|
u8x8.setCursor(11, 3);
|
||||||
|
u8x8.printf("SF:");
|
||||||
|
if (cfg.adrmode) // if ADR=on then display SF value inverse
|
||||||
|
u8x8.setInverseFont(1);
|
||||||
|
u8x8.printf("%c%c", lora_datarate[LMIC.datarate * 2],
|
||||||
|
lora_datarate[LMIC.datarate * 2 + 1]);
|
||||||
|
if (cfg.adrmode) // switch off inverse if it was turned on
|
||||||
|
u8x8.setInverseFont(0);
|
||||||
|
|
||||||
// update LoRa SF display (line 3)
|
// update wifi counter + channel display (line 4)
|
||||||
u8x8.setCursor(11,3);
|
u8x8.setCursor(0, 4);
|
||||||
u8x8.printf("SF:%c%c", lora_datarate[LMIC.datarate * 2], lora_datarate[LMIC.datarate * 2 + 1]);
|
u8x8.printf("WIFI:%-4d", macs_wifi);
|
||||||
|
u8x8.setCursor(11, 4);
|
||||||
// update wifi channel display (line 4)
|
|
||||||
u8x8.setCursor(11,4);
|
|
||||||
u8x8.printf("ch:%02d", channel);
|
u8x8.printf("ch:%02d", channel);
|
||||||
|
|
||||||
// update RSSI limiter status & free memory display (line 5)
|
// update RSSI limiter status & free memory display (line 5)
|
||||||
u8x8.setCursor(0,5);
|
u8x8.setCursor(0, 5);
|
||||||
u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%-4d", cfg.rssilimit);
|
u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%-4d", cfg.rssilimit);
|
||||||
u8x8.setCursor(10,5);
|
u8x8.setCursor(10, 5);
|
||||||
u8x8.printf("%4dKB", ESP.getFreeHeap() / 1024);
|
u8x8.printf("%4dKB", ESP.getFreeHeap() / 1024);
|
||||||
|
|
||||||
// update LoRa status display (line 6)
|
// update LoRa status display (line 6)
|
||||||
u8x8.setCursor(0,6);
|
u8x8.setCursor(0, 6);
|
||||||
u8x8.printf("%-16s", display_lora);
|
u8x8.printf("%-16s", display_lora);
|
||||||
|
|
||||||
// update LMiC event display (line 7)
|
// update LMiC event display (line 7)
|
||||||
u8x8.setCursor(0,7);
|
u8x8.setCursor(0, 7);
|
||||||
u8x8.printf("%-16s", display_lmic);
|
u8x8.printf("%-16s", display_lmic);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDisplay() {
|
void updateDisplay() {
|
||||||
// refresh display according to refresh cycle setting
|
// refresh display according to refresh cycle setting
|
||||||
if (DisplayTimerIRQ) {
|
if (DisplayTimerIRQ) {
|
||||||
portENTER_CRITICAL(&timerMux);
|
portENTER_CRITICAL(&timerMux);
|
||||||
@ -368,41 +361,45 @@ uint64_t uptime() {
|
|||||||
u8x8.setPowerSave(!cfg.screenon);
|
u8x8.setPowerSave(!cfg.screenon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // updateDisplay()
|
} // updateDisplay()
|
||||||
#endif // HAS_DISPLAY
|
#endif // HAS_DISPLAY
|
||||||
|
|
||||||
#ifdef HAS_BUTTON
|
#ifdef HAS_BUTTON
|
||||||
void readButton() {
|
void readButton() {
|
||||||
if (ButtonPressed) {
|
if (ButtonPressedIRQ) {
|
||||||
ButtonPressed--;
|
portENTER_CRITICAL(&timerMux);
|
||||||
|
ButtonPressedIRQ--;
|
||||||
|
portEXIT_CRITICAL(&timerMux);
|
||||||
|
ESP_LOGI(TAG, "Button pressed");
|
||||||
ESP_LOGI(TAG, "Button pressed, resetting device to factory defaults");
|
ESP_LOGI(TAG, "Button pressed, resetting device to factory defaults");
|
||||||
eraseConfig();
|
eraseConfig();
|
||||||
esp_restart();
|
esp_restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (HAS_LED != NOT_A_PIN) || defined (HAS_RGB_LED)
|
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||||
void blink_LED(uint16_t set_color, uint16_t set_blinkduration) {
|
|
||||||
|
void blink_LED(uint16_t set_color, uint16_t set_blinkduration) {
|
||||||
LEDColor = set_color; // set color for RGB LED
|
LEDColor = set_color; // set color for RGB LED
|
||||||
LEDBlinkDuration = set_blinkduration; // duration
|
LEDBlinkDuration = set_blinkduration; // duration
|
||||||
LEDBlinkStarted = millis(); // Time Start here
|
LEDBlinkStarted = millis(); // Time Start here
|
||||||
LEDState = LED_ON; // Let main set LED on
|
LEDState = LED_ON; // Let main set LED on
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_loop() {
|
void led_loop() {
|
||||||
// Custom blink running always have priority other LoRaWAN led management
|
// Custom blink running always have priority other LoRaWAN led management
|
||||||
if ( LEDBlinkStarted && LEDBlinkDuration) {
|
if (LEDBlinkStarted && LEDBlinkDuration) {
|
||||||
|
|
||||||
//ESP_LOGI(TAG, "Start=%ld for %g",LEDBlinkStarted, LEDBlinkDuration );
|
// ESP_LOGI(TAG, "Start=%ld for %g",LEDBlinkStarted, LEDBlinkDuration );
|
||||||
|
|
||||||
// Custom blink is finished, let this order, avoid millis() overflow
|
// Custom blink is finished, let this order, avoid millis() overflow
|
||||||
if ( (millis() - LEDBlinkStarted) >= LEDBlinkDuration) {
|
if ((millis() - LEDBlinkStarted) >= LEDBlinkDuration) {
|
||||||
// Led becomes off, and stop blink
|
// Led becomes off, and stop blink
|
||||||
LEDState = LED_OFF;
|
LEDState = LED_OFF;
|
||||||
LEDBlinkStarted = 0;
|
LEDBlinkStarted = 0;
|
||||||
LEDBlinkDuration = 0;
|
LEDBlinkDuration = 0;
|
||||||
LEDColor = COLOR_NONE ;
|
LEDColor = COLOR_NONE;
|
||||||
} else {
|
} else {
|
||||||
// In case of LoRaWAN led management blinked off
|
// In case of LoRaWAN led management blinked off
|
||||||
LEDState = LED_ON;
|
LEDState = LED_ON;
|
||||||
@ -412,7 +409,7 @@ uint64_t uptime() {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
// LED indicators for viusalizing LoRaWAN state
|
// LED indicators for viusalizing LoRaWAN state
|
||||||
if ( LMIC.opmode & (OP_JOINING | OP_REJOIN) ) {
|
if (LMIC.opmode & (OP_JOINING | OP_REJOIN)) {
|
||||||
LEDColor = COLOR_YELLOW;
|
LEDColor = COLOR_YELLOW;
|
||||||
// quick blink 20ms on each 1/5 second
|
// quick blink 20ms on each 1/5 second
|
||||||
LEDState = ((millis() % 200) < 20) ? LED_ON : LED_OFF; // TX data pending
|
LEDState = ((millis() % 200) < 20) ? LED_ON : LED_OFF; // TX data pending
|
||||||
@ -421,7 +418,8 @@ uint64_t uptime() {
|
|||||||
// small blink 10ms on each 1/2sec (not when joining)
|
// small blink 10ms on each 1/2sec (not when joining)
|
||||||
LEDState = ((millis() % 500) < 20) ? LED_ON : LED_OFF;
|
LEDState = ((millis() % 500) < 20) ? LED_ON : LED_OFF;
|
||||||
// This should not happen so indicate a problem
|
// This should not happen so indicate a problem
|
||||||
} else if ( LMIC.opmode & (OP_TXDATA | OP_TXRXPEND | OP_JOINING | OP_REJOIN) == 0 ) {
|
} else if (LMIC.opmode &
|
||||||
|
((OP_TXDATA | OP_TXRXPEND | OP_JOINING | OP_REJOIN) == 0)) {
|
||||||
LEDColor = COLOR_RED;
|
LEDColor = COLOR_RED;
|
||||||
// heartbeat long blink 200ms on each 2 seconds
|
// heartbeat long blink 200ms on each 2 seconds
|
||||||
LEDState = ((millis() % 2000) < 200) ? LED_ON : LED_OFF;
|
LEDState = ((millis() % 2000) < 200) ? LED_ON : LED_OFF;
|
||||||
@ -432,32 +430,33 @@ uint64_t uptime() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ESP_LOGI(TAG, "state=%d previous=%d Color=%d",LEDState, previousLEDState, LEDColor );
|
// ESP_LOGI(TAG, "state=%d previous=%d Color=%d",LEDState, previousLEDState,
|
||||||
|
// LEDColor );
|
||||||
// led need to change state? avoid digitalWrite() for nothing
|
// led need to change state? avoid digitalWrite() for nothing
|
||||||
if (LEDState != previousLEDState) {
|
if (LEDState != previousLEDState) {
|
||||||
if (LEDState == LED_ON) {
|
if (LEDState == LED_ON) {
|
||||||
rgb_set_color(LEDColor);
|
rgb_set_color(LEDColor);
|
||||||
#ifdef LED_ACTIVE_LOW
|
#ifdef LED_ACTIVE_LOW
|
||||||
digitalWrite(HAS_LED, LOW);
|
digitalWrite(HAS_LED, LOW);
|
||||||
#else
|
#else
|
||||||
digitalWrite(HAS_LED, HIGH);
|
digitalWrite(HAS_LED, HIGH);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
rgb_set_color(COLOR_NONE);
|
rgb_set_color(COLOR_NONE);
|
||||||
#ifdef LED_ACTIVE_LOW
|
#ifdef LED_ACTIVE_LOW
|
||||||
digitalWrite(HAS_LED, HIGH);
|
digitalWrite(HAS_LED, HIGH);
|
||||||
#else
|
#else
|
||||||
digitalWrite(HAS_LED, LOW);
|
digitalWrite(HAS_LED, LOW);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
previousLEDState = LEDState;
|
previousLEDState = LEDState;
|
||||||
}
|
}
|
||||||
}; // led_loop()
|
}; // led_loop()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* begin Aruino SETUP
|
||||||
/* begin Aruino SETUP ------------------------------------------------------------ */
|
* ------------------------------------------------------------ */
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
char features[64] = "";
|
char features[64] = "";
|
||||||
@ -465,7 +464,7 @@ void setup() {
|
|||||||
// disable brownout detection
|
// disable brownout detection
|
||||||
#ifdef DISABLE_BROWNOUT
|
#ifdef DISABLE_BROWNOUT
|
||||||
// register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
|
// register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
|
||||||
(*((volatile uint32_t *)ETS_UNCACHED_ADDR((DR_REG_RTCCNTL_BASE+0xd4)))) = 0;
|
(*((volatile uint32_t *)ETS_UNCACHED_ADDR((DR_REG_RTCCNTL_BASE + 0xd4)))) = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// setup debug output or silence device
|
// setup debug output or silence device
|
||||||
@ -480,22 +479,29 @@ void setup() {
|
|||||||
|
|
||||||
ESP_LOGI(TAG, "Starting %s %s", PROGNAME, PROGVERSION);
|
ESP_LOGI(TAG, "Starting %s %s", PROGNAME, PROGVERSION);
|
||||||
|
|
||||||
// initialize system event handler for wifi task, needed for wifi_sniffer_init()
|
// initialize system event handler for wifi task, needed for
|
||||||
|
// wifi_sniffer_init()
|
||||||
esp_event_loop_init(NULL, NULL);
|
esp_event_loop_init(NULL, NULL);
|
||||||
|
|
||||||
// print chip information on startup if in verbose mode
|
// print chip information on startup if in verbose mode
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
esp_chip_info_t chip_info;
|
esp_chip_info_t chip_info;
|
||||||
esp_chip_info(&chip_info);
|
esp_chip_info(&chip_info);
|
||||||
ESP_LOGI(TAG, "This is ESP32 chip with %d CPU cores, WiFi%s%s, silicon revision %d, %dMB %s Flash",
|
ESP_LOGI(TAG,
|
||||||
chip_info.cores,
|
"This is ESP32 chip with %d CPU cores, WiFi%s%s, silicon revision "
|
||||||
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
"%d, %dMB %s Flash",
|
||||||
|
chip_info.cores, (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
||||||
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
|
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
|
||||||
chip_info.revision, spi_flash_get_chip_size() / (1024 * 1024),
|
chip_info.revision, spi_flash_get_chip_size() / (1024 * 1024),
|
||||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
|
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded"
|
||||||
|
: "external");
|
||||||
ESP_LOGI(TAG, "ESP32 SDK: %s", ESP.getSdkVersion());
|
ESP_LOGI(TAG, "ESP32 SDK: %s", ESP.getSdkVersion());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_GPS
|
||||||
|
ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion());
|
||||||
|
#endif
|
||||||
|
|
||||||
// read settings from NVRAM
|
// read settings from NVRAM
|
||||||
loadConfig(); // includes initialize if necessary
|
loadConfig(); // includes initialize if necessary
|
||||||
|
|
||||||
@ -508,24 +514,22 @@ void setup() {
|
|||||||
#ifdef HAS_RGB_LED
|
#ifdef HAS_RGB_LED
|
||||||
rgb_set_color(COLOR_PINK);
|
rgb_set_color(COLOR_PINK);
|
||||||
strcat(features, " RGB");
|
strcat(features, " RGB");
|
||||||
delay(1000);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// initialize button handling if needed
|
// initialize button handling if needed
|
||||||
#ifdef HAS_BUTTON
|
#ifdef HAS_BUTTON
|
||||||
strcat(features, " BTN_");
|
strcat(features, " BTN_");
|
||||||
#ifdef BUTTON_PULLUP
|
#ifdef BUTTON_PULLUP
|
||||||
strcat(features, "PU");
|
strcat(features, "PU");
|
||||||
// install button interrupt (pullup mode)
|
// install button interrupt (pullup mode)
|
||||||
pinMode(HAS_BUTTON, INPUT_PULLUP);
|
pinMode(HAS_BUTTON, INPUT_PULLUP);
|
||||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
|
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
|
||||||
#else
|
#else
|
||||||
strcat(features, "PD");
|
strcat(features, "PD");
|
||||||
// install button interrupt (pulldown mode)
|
// install button interrupt (pulldown mode)
|
||||||
pinMode(HAS_BUTTON, INPUT_PULLDOWN);
|
pinMode(HAS_BUTTON, INPUT_PULLDOWN);
|
||||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING);
|
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize wifi antenna if needed
|
// initialize wifi antenna if needed
|
||||||
@ -534,6 +538,11 @@ void setup() {
|
|||||||
antenna_init();
|
antenna_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// initialize gps if present
|
||||||
|
#ifdef HAS_GPS
|
||||||
|
strcat(features, " GPS");
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
strcat(features, " OLED");
|
strcat(features, " OLED");
|
||||||
// initialize display
|
// initialize display
|
||||||
@ -541,100 +550,141 @@ void setup() {
|
|||||||
DisplayState = cfg.screenon;
|
DisplayState = cfg.screenon;
|
||||||
u8x8.setPowerSave(!cfg.screenon); // set display off if disabled
|
u8x8.setPowerSave(!cfg.screenon); // set display off if disabled
|
||||||
u8x8.draw2x2String(0, 0, "PAX:0");
|
u8x8.draw2x2String(0, 0, "PAX:0");
|
||||||
u8x8.setCursor(0,4);
|
#ifdef BLECOUNTER
|
||||||
u8x8.printf("WIFI:0");
|
u8x8.setCursor(0, 3);
|
||||||
#ifdef BLECOUNTER
|
|
||||||
u8x8.setCursor(0,3);
|
|
||||||
u8x8.printf("BLTH:0");
|
u8x8.printf("BLTH:0");
|
||||||
#endif
|
#endif
|
||||||
u8x8.setCursor(0,5);
|
u8x8.setCursor(0, 4);
|
||||||
|
u8x8.printf("WIFI:0");
|
||||||
|
u8x8.setCursor(0, 5);
|
||||||
u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%d", cfg.rssilimit);
|
u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%d", cfg.rssilimit);
|
||||||
|
|
||||||
sprintf(display_lora, "Join wait");
|
sprintf(display_lora, "Join wait");
|
||||||
|
|
||||||
// setup Display IRQ, thanks to https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
|
// setup display refresh trigger IRQ using esp32 hardware timer 0
|
||||||
displaytimer = timerBegin(0, 80, true); // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up
|
// for explanation see
|
||||||
timerAttachInterrupt(displaytimer, &DisplayIRQ, true); // interrupt handler DisplayIRQ, triggered by edge
|
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
|
||||||
timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true); // reload interrupt after each trigger of display refresh cycle
|
displaytimer = timerBegin(0, 80, true); // prescaler 80 -> divides 80 MHz CPU
|
||||||
|
// freq to 1 MHz, timer 0, count up
|
||||||
|
timerAttachInterrupt(displaytimer, &DisplayIRQ,
|
||||||
|
true); // interrupt handler DisplayIRQ, triggered by edge
|
||||||
|
timerAlarmWrite(
|
||||||
|
displaytimer, DISPLAYREFRESH_MS * 1000,
|
||||||
|
true); // reload interrupt after each trigger of display refresh cycle
|
||||||
timerAlarmEnable(displaytimer); // enable display interrupt
|
timerAlarmEnable(displaytimer); // enable display interrupt
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// setup channel rotation IRQ, thanks to https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
|
// setup channel rotation trigger IRQ using esp32 hardware timer 1
|
||||||
channelSwitch = timerBegin(1, 80, true); // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 1, count up
|
channelSwitch = timerBegin(1, 80, true);
|
||||||
timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true); // interrupt handler, triggered by edge
|
timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true);
|
||||||
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 10000, true); // reload interrupt after each trigger of channel switch cycle
|
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 10000, true);
|
||||||
timerAlarmEnable(channelSwitch); // enable channel switching interrupt
|
timerAlarmEnable(channelSwitch);
|
||||||
|
|
||||||
// show compiled features
|
// show compiled features
|
||||||
ESP_LOGI(TAG, "Features %s", features);
|
ESP_LOGI(TAG, "Features %s", features);
|
||||||
|
|
||||||
// output LoRaWAN keys to console
|
// output LoRaWAN keys to console
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
printKeys();
|
printKeys();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
os_init(); // setup LMIC
|
// initialize LoRaWAN LMIC run-time environment
|
||||||
LMIC_reset(); // Reset the MAC state. Session and pending data transfers will be discarded.
|
os_init();
|
||||||
os_setCallback(&initjob, lora_init); // setup initial job & join network
|
// 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);
|
||||||
|
|
||||||
wifi_sniffer_init(); // setup wifi in monitor mode and start MAC counting
|
// 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/
|
||||||
|
|
||||||
// initialize salt value using esp_random() called by random() in arduino-esp32 core
|
ESP_LOGI(TAG, "Starting Lora task on core 1");
|
||||||
// note: do this *after* wifi has started, since gets it's seed from RF noise
|
xTaskCreatePinnedToCore(lorawan_loop, "loratask", 2048, (void *)1,
|
||||||
reset_salt(); // get new 16bit for salting hashes
|
(5 | portPRIVILEGE_BIT), NULL, 1);
|
||||||
|
|
||||||
// run wifi task on core 0 and lora task on core 1 and bt task on core 0
|
// start wifi in monitor mode and start channel rotation task on core 0
|
||||||
ESP_LOGI(TAG, "Starting Lora task on core 1");
|
ESP_LOGI(TAG, "Starting Wifi task on core 0");
|
||||||
xTaskCreatePinnedToCore(lorawan_loop, "loratask", 2048, ( void * ) 1, ( 5 | portPRIVILEGE_BIT ), NULL, 1);
|
wifi_sniffer_init();
|
||||||
|
// initialize salt value using esp_random() called by random() in
|
||||||
ESP_LOGI(TAG, "Starting Wifi task on core 0");
|
// arduino-esp32 core note: do this *after* wifi has started, since function
|
||||||
xTaskCreatePinnedToCore(sniffer_loop, "wifisniffer", 2048, ( void * ) 1, 1, NULL, 0);
|
// gets it's seed from RF noise
|
||||||
|
reset_salt(); // get new 16bit for salting hashes
|
||||||
|
xTaskCreatePinnedToCore(sniffer_loop, "wifisniffer", 2048, (void *)1, 1, NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
// start BLE scan callback if BLE function is enabled in NVRAM configuration
|
||||||
#ifdef BLECOUNTER
|
#ifdef BLECOUNTER
|
||||||
if (cfg.blescan) { // start BLE task only if BLE function is enabled in NVRAM configuration
|
if (cfg.blescan) {
|
||||||
ESP_LOGI(TAG, "Starting Bluetooth task on core 0");
|
start_BLEscan();
|
||||||
xTaskCreatePinnedToCore(bt_loop, "btscan", 4096, ( void * ) 1, 1, NULL, 0);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Finally: kickoff first sendjob and join, then send initial payload "0000"
|
// if device has GPS and GPS function is enabled, start GPS reader task on core
|
||||||
uint8_t mydata[] = "0000";
|
// 0
|
||||||
do_send(&sendjob);
|
#ifdef HAS_GPS
|
||||||
|
if (cfg.gpsmode) {
|
||||||
|
ESP_LOGI(TAG, "Starting GPS task on core 0");
|
||||||
|
xTaskCreatePinnedToCore(gps_loop, "gpsfeed", 2048, (void *)1, 1, NULL, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// kickoff sendjob -> joins network and rescedules sendjob for cyclic
|
||||||
|
// transmitting payload
|
||||||
|
do_send(&sendjob);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end Aruino SETUP ------------------------------------------------------------ */
|
/* end Arduino SETUP
|
||||||
|
* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* begin Arduino main loop
|
||||||
|
* ------------------------------------------------------ */
|
||||||
|
|
||||||
/* begin Aruino LOOP ------------------------------------------------------------ */
|
|
||||||
|
|
||||||
// Arduino main moop, runs on core 1
|
|
||||||
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
// simple state machine for controlling display, LED, button, etc.
|
while (1) {
|
||||||
|
|
||||||
|
// simple state machine for controlling uptime, display, LED, button,
|
||||||
|
// memory.
|
||||||
|
|
||||||
uptimecounter = uptime() / 1000; // counts uptime in seconds (64bit)
|
uptimecounter = uptime() / 1000; // counts uptime in seconds (64bit)
|
||||||
|
|
||||||
#if (HAS_LED != NOT_A_PIN) || defined (HAS_RGB_LED)
|
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||||
led_loop();
|
led_loop();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_BUTTON
|
#ifdef HAS_BUTTON
|
||||||
readButton();
|
readButton();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// check free memory
|
// check free memory
|
||||||
if (ESP.getFreeHeap() <= MEM_LOW) {
|
if (esp_get_minimum_free_heap_size() <= MEM_LOW) {
|
||||||
|
ESP_LOGI(TAG,
|
||||||
|
"Memory full, counter cleared (heap low water mark = %d Bytes / "
|
||||||
|
"free heap = %d bytes)",
|
||||||
|
esp_get_minimum_free_heap_size(), ESP.getFreeHeap());
|
||||||
do_send(&sendjob); // send count
|
do_send(&sendjob); // send count
|
||||||
reset_counters(); // clear macs container and reset all counters
|
reset_counters(); // clear macs container and reset all counters
|
||||||
reset_salt(); // get new salt for salting hashes
|
reset_salt(); // get new salt for salting hashes
|
||||||
}
|
}
|
||||||
|
|
||||||
vTaskDelay(10/portTICK_PERIOD_MS); // reset watchdog
|
#ifdef HAS_GPS
|
||||||
|
// log NMEA status every 30 seconds, useful for debugging GPS connection
|
||||||
|
if ((uptime() % 30000) == 0)
|
||||||
|
ESP_LOGI(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d",
|
||||||
|
gps.passedChecksum(), gps.failedChecksum(),
|
||||||
|
gps.sentencesWithFix());
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
vTaskDelay(1 / portTICK_PERIOD_MS); // reset watchdog
|
||||||
|
|
||||||
/* end Aruino LOOP ------------------------------------------------------------ */
|
} // end of infinite main loop
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end Arduino main loop
|
||||||
|
* ------------------------------------------------------------ */
|
||||||
|
46
src/main.h
46
src/main.h
@ -1,19 +1,21 @@
|
|||||||
|
|
||||||
// program version - note: increment version after modifications to configData_t struct!!
|
#include "configmanager.h"
|
||||||
#define PROGVERSION "1.3.4" // use max 10 chars here!
|
#include "lorawan.h"
|
||||||
|
#include "macsniff.h"
|
||||||
|
|
||||||
|
// program version - note: increment version after modifications to configData_t
|
||||||
|
// struct!!
|
||||||
|
#define PROGVERSION "1.3.81" // use max 10 chars here!
|
||||||
#define PROGNAME "PAXCNT"
|
#define PROGNAME "PAXCNT"
|
||||||
|
|
||||||
//--- Declarations ---
|
//--- Declarations ---
|
||||||
|
|
||||||
enum led_states {
|
enum led_states { LED_OFF, LED_ON };
|
||||||
LED_OFF,
|
|
||||||
LED_ON
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(CFG_eu868)
|
#if defined(CFG_eu868)
|
||||||
const char lora_datarate[] = {"1211100908077BFSNA"};
|
const char lora_datarate[] = {"1211100908077BFSNA"};
|
||||||
#elif defined(CFG_us915)
|
#elif defined(CFG_us915)
|
||||||
const char lora_datarate[] = {"100908078CNA121110090807"};
|
const char lora_datarate[] = {"100908078CNA121110090807"};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--- Prototypes ---
|
//--- Prototypes ---
|
||||||
@ -23,22 +25,14 @@ void reset_counters(void);
|
|||||||
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
|
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
|
||||||
void led_loop(void);
|
void led_loop(void);
|
||||||
|
|
||||||
// defined in configmanager.cpp
|
|
||||||
void eraseConfig(void);
|
|
||||||
void saveConfig(void);
|
|
||||||
void loadConfig(void);
|
|
||||||
|
|
||||||
// defined in lorawan.cpp
|
|
||||||
void onEvent(ev_t ev);
|
|
||||||
void do_send(osjob_t* j);
|
|
||||||
void gen_lora_deveui(uint8_t * pdeveui);
|
|
||||||
void RevBytes(unsigned char* b, size_t c);
|
|
||||||
void get_hard_deveui(uint8_t *pdeveui);
|
|
||||||
|
|
||||||
// defined in wifisniffer.cpp
|
|
||||||
void wifi_sniffer_init(void);
|
|
||||||
void wifi_sniffer_set_channel(uint8_t channel);
|
|
||||||
void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
|
||||||
|
|
||||||
// defined in blescan.cpp
|
// defined in blescan.cpp
|
||||||
void bt_loop(void *ignore);
|
#ifdef BLECOUNTER
|
||||||
|
void start_BLEscan(void);
|
||||||
|
void stop_BLEscan(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// defined in gpsread.cpp
|
||||||
|
#ifdef HAS_GPS
|
||||||
|
void gps_read(void);
|
||||||
|
void gps_loop(void *pvParameters);
|
||||||
|
#endif
|
||||||
|
@ -7,23 +7,25 @@
|
|||||||
|
|
||||||
// set this to include BLE counting and vendor filter functions
|
// set this to include BLE counting and vendor filter functions
|
||||||
#define VENDORFILTER 1 // comment out if you want to count things, not people
|
#define VENDORFILTER 1 // comment out if you want to count things, not people
|
||||||
#define BLECOUNTER 1 // comment out if you don't want BLE count
|
#define BLECOUNTER 1 // comment out if you don't want BLE count, saves power & memory
|
||||||
|
|
||||||
// BLE scan parameters
|
// BLE scan parameters
|
||||||
#define BLESCANTIME 11 // [seconds] scan duration, see note below
|
#define BLESTACKSIZE 8192 // stack size for esp_bt_controller
|
||||||
#define BLESCANWINDOW 10 // [milliseconds] scan window, see below, 3 .. 10240, default 10
|
#define BLESCANTIME 0 // [seconds] scan duration, 0 means infinite [default], see note below
|
||||||
#define BLESCANINTERVAL 10 // [milliseconds] how long to wait between scans, 3 .. 10240, default 10
|
#define BLESCANWINDOW 80 // [milliseconds] scan window, see below, 3 .. 10240, default 80ms
|
||||||
|
#define BLESCANINTERVAL 80 // [illiseconds] scan interval, see below, 3 .. 10240, default 80ms = 100% duty cycle
|
||||||
|
|
||||||
/* Note: guide for setting bluetooth parameters
|
/* Note: guide for setting bluetooth parameters
|
||||||
*
|
*
|
||||||
* |< Scan Window > |< Scan Window > |< Scan Window > |
|
* |< Scan Window > |< Scan Window > | ... |< Scan Window > |
|
||||||
* |< Scan Interval >|< Scan Interval >|< Scan Interval >|
|
* |< Scan Interval >|< Scan Interval >| ... |< Scan Interval >|
|
||||||
* |< Scan duration >|
|
* |< Scan duration >|
|
||||||
*
|
*
|
||||||
* Scan duration sets how long scanning should be going on, interrupting a wifi scan cycle.
|
* Scan duration sets how long scanning should be going on, before starting a new scan cycle. 0 means infinite (default).
|
||||||
* Scan window sets how much of the interval should be occupied by scanning.
|
* Scan window sets how much of the interval should be occupied by scanning. Should be >= BLESCANINTERVAL.
|
||||||
* Scan interval is how long scanning should be done on each channel. BLE uses 3 channels for advertising.
|
* Scan interval is how long scanning should be done on each channel. BLE uses 3 channels for advertising.
|
||||||
* -> Adjust these values with power consumption in mind if power is limited.
|
* -> Adjust these values with power consumption in mind if power is limited.
|
||||||
|
* -> Scan interval can be changed during runtime by remote comammand.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// WiFi scan parameters
|
// WiFi scan parameters
|
||||||
@ -35,11 +37,14 @@
|
|||||||
// LoRa payload send cycle --> take care of duty cycle of LoRaWAN network! <--
|
// LoRa payload send cycle --> take care of duty cycle of LoRaWAN network! <--
|
||||||
#define SEND_SECS 120 // [seconds/2] -> 240 sec.
|
#define SEND_SECS 120 // [seconds/2] -> 240 sec.
|
||||||
#define MEM_LOW 2048 // [Bytes] low memory threshold triggering a send cycle
|
#define MEM_LOW 2048 // [Bytes] low memory threshold triggering a send cycle
|
||||||
|
#define RETRANSMIT_RCMD 5 // [seconds] wait time before retransmitting rcommand results
|
||||||
|
|
||||||
// Default LoRa Spreadfactor
|
// Default LoRa Spreadfactor
|
||||||
#define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs
|
#define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs
|
||||||
#define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy
|
#define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy
|
||||||
#define RCMDPORT 2 // LoRaWAN Port on which device listenes for remote commands
|
#define RCMDPORT 2 // LoRaWAN Port on which device listenes for remote commands
|
||||||
|
#define GPSPORT 3 // LoRaWAN Port on which device sends gps data
|
||||||
|
#define COUNTERPORT 1 // LoRaWAN Port on which device sends counts
|
||||||
|
|
||||||
// Default RGB LED luminosity (in %)
|
// Default RGB LED luminosity (in %)
|
||||||
#define RGBLUMINOSITY 30 // 30%
|
#define RGBLUMINOSITY 30 // 30%
|
||||||
|
294
src/rcommand.cpp
294
src/rcommand.cpp
@ -1,6 +1,7 @@
|
|||||||
// remote command interpreter
|
// remote command interpreter
|
||||||
// parses multiple number of command / value pairs from LoRaWAN remote command port (RCMDPORT)
|
// parses multiple number of command / value pairs from LoRaWAN remote command
|
||||||
// checks commands and executes each command with 1 argument per command
|
// port (RCMDPORT) checks commands and executes each command with 1 argument per
|
||||||
|
// command
|
||||||
|
|
||||||
// Basic Config
|
// Basic Config
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
@ -10,7 +11,7 @@
|
|||||||
#include <hal/hal.h>
|
#include <hal/hal.h>
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char *TAG = "rcommand";
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
// table of remote commands and assigned functions
|
// table of remote commands and assigned functions
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -21,31 +22,82 @@ typedef struct {
|
|||||||
|
|
||||||
// function defined in antenna.cpp
|
// function defined in antenna.cpp
|
||||||
#ifdef HAS_ANTENNA_SWITCH
|
#ifdef HAS_ANTENNA_SWITCH
|
||||||
void antenna_select(const uint8_t _ant);
|
void antenna_select(const uint8_t _ant);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// function defined in adcread.cpp
|
||||||
|
#ifdef HAS_BATTERY_PROBE
|
||||||
|
uint32_t read_voltage(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// function sends result of get commands to LoRaWAN network
|
||||||
|
void do_transmit(osjob_t *j) {
|
||||||
|
// check if there is a pending TX/RX job running, if yes then reschedule
|
||||||
|
// transmission
|
||||||
|
if (LMIC.opmode & OP_TXRXPEND) {
|
||||||
|
ESP_LOGI(TAG, "LoRa busy, rescheduling");
|
||||||
|
sprintf(display_lmic, "LORA BUSY");
|
||||||
|
os_setTimedCallback(&rcmdjob, os_getTime() + sec2osticks(RETRANSMIT_RCMD),
|
||||||
|
do_transmit);
|
||||||
|
}
|
||||||
|
LMIC_setTxData2(RCMDPORT, rcmd_data, rcmd_data_size,
|
||||||
|
0); // send data unconfirmed on RCMD Port
|
||||||
|
ESP_LOGI(TAG, "%d bytes queued to send", rcmd_data_size);
|
||||||
|
sprintf(display_lmic, "PACKET QUEUED");
|
||||||
|
}
|
||||||
|
|
||||||
|
// help function to transmit result of get commands, since callback function
|
||||||
|
// do_transmit() cannot have params
|
||||||
|
void transmit(xref2u1_t mydata, u1_t mydata_size) {
|
||||||
|
rcmd_data = mydata;
|
||||||
|
rcmd_data_size = mydata_size;
|
||||||
|
do_transmit(&rcmdjob);
|
||||||
|
}
|
||||||
|
|
||||||
// help function to assign LoRa datarates to numeric spreadfactor values
|
// help function to assign LoRa datarates to numeric spreadfactor values
|
||||||
void switch_lora (uint8_t sf, uint8_t tx) {
|
void switch_lora(uint8_t sf, uint8_t tx) {
|
||||||
if ( tx > 20 ) return;
|
if (tx > 20)
|
||||||
|
return;
|
||||||
cfg.txpower = tx;
|
cfg.txpower = tx;
|
||||||
switch (sf) {
|
switch (sf) {
|
||||||
case 7: LMIC_setDrTxpow(DR_SF7,tx); cfg.lorasf=sf; break;
|
case 7:
|
||||||
case 8: LMIC_setDrTxpow(DR_SF8,tx); cfg.lorasf=sf; break;
|
LMIC_setDrTxpow(DR_SF7, tx);
|
||||||
case 9: LMIC_setDrTxpow(DR_SF9,tx); cfg.lorasf=sf; break;
|
cfg.lorasf = sf;
|
||||||
case 10: LMIC_setDrTxpow(DR_SF10,tx); cfg.lorasf=sf; break;
|
break;
|
||||||
|
case 8:
|
||||||
|
LMIC_setDrTxpow(DR_SF8, tx);
|
||||||
|
cfg.lorasf = sf;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
LMIC_setDrTxpow(DR_SF9, tx);
|
||||||
|
cfg.lorasf = sf;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
LMIC_setDrTxpow(DR_SF10, tx);
|
||||||
|
cfg.lorasf = sf;
|
||||||
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
#if defined(CFG_eu868)
|
#if defined(CFG_eu868)
|
||||||
LMIC_setDrTxpow(DR_SF11,tx); cfg.lorasf=sf; break;
|
LMIC_setDrTxpow(DR_SF11, tx);
|
||||||
#elif defined(CFG_us915)
|
cfg.lorasf = sf;
|
||||||
LMIC_setDrTxpow(DR_SF11CR,tx); cfg.lorasf=sf; break;
|
break;
|
||||||
#endif
|
#elif defined(CFG_us915)
|
||||||
|
LMIC_setDrTxpow(DR_SF11CR, tx);
|
||||||
|
cfg.lorasf = sf;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case 12:
|
case 12:
|
||||||
#if defined(CFG_eu868)
|
#if defined(CFG_eu868)
|
||||||
LMIC_setDrTxpow(DR_SF12,tx); cfg.lorasf=sf; break;
|
LMIC_setDrTxpow(DR_SF12, tx);
|
||||||
#elif defined(CFG_us915)
|
cfg.lorasf = sf;
|
||||||
LMIC_setDrTxpow(DR_SF12CR,tx); cfg.lorasf=sf; break;
|
break;
|
||||||
#endif
|
#elif defined(CFG_us915)
|
||||||
default: break;
|
LMIC_setDrTxpow(DR_SF12CR, tx);
|
||||||
|
cfg.lorasf = sf;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +107,9 @@ void set_reset(uint8_t val) {
|
|||||||
case 0: // restart device
|
case 0: // restart device
|
||||||
ESP_LOGI(TAG, "Remote command: restart device");
|
ESP_LOGI(TAG, "Remote command: restart device");
|
||||||
sprintf(display_lora, "Reset pending");
|
sprintf(display_lora, "Reset pending");
|
||||||
vTaskDelay(10000/portTICK_PERIOD_MS); // wait for LMIC to confirm LoRa downlink to server
|
vTaskDelay(
|
||||||
|
10000 /
|
||||||
|
portTICK_PERIOD_MS); // wait for LMIC to confirm LoRa downlink to server
|
||||||
esp_restart();
|
esp_restart();
|
||||||
break;
|
break;
|
||||||
case 1: // reset MAC counter
|
case 1: // reset MAC counter
|
||||||
@ -79,19 +133,32 @@ void set_rssi(uint8_t val) {
|
|||||||
|
|
||||||
void set_sendcycle(uint8_t val) {
|
void set_sendcycle(uint8_t val) {
|
||||||
cfg.sendcycle = val;
|
cfg.sendcycle = val;
|
||||||
ESP_LOGI(TAG, "Remote command: set payload send cycle to %d seconds", cfg.sendcycle*2);
|
ESP_LOGI(TAG, "Remote command: set payload send cycle to %d seconds",
|
||||||
|
cfg.sendcycle * 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_wifichancycle(uint8_t val) {
|
void set_wifichancycle(uint8_t val) {
|
||||||
cfg.wifichancycle = val;
|
cfg.wifichancycle = val;
|
||||||
// modify wifi channel rotation IRQ
|
// modify wifi channel rotation IRQ
|
||||||
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 10000, true); // reload interrupt after each trigger of channel switch cycle
|
timerAlarmWrite(
|
||||||
ESP_LOGI(TAG, "Remote command: set Wifi channel switch interval to %.1f seconds", cfg.wifichancycle/float(100));
|
channelSwitch, cfg.wifichancycle * 10000,
|
||||||
|
true); // reload interrupt after each trigger of channel switch cycle
|
||||||
|
ESP_LOGI(TAG,
|
||||||
|
"Remote command: set Wifi channel switch interval to %.1f seconds",
|
||||||
|
cfg.wifichancycle / float(100));
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_blescantime(uint8_t val) {
|
void set_blescantime(uint8_t val) {
|
||||||
cfg.blescantime = val;
|
cfg.blescantime = val;
|
||||||
ESP_LOGI(TAG, "Remote command: set BLE scan time to %d seconds", cfg.blescantime);
|
ESP_LOGI(TAG, "Remote command: set BLE scan time to %.1f seconds",
|
||||||
|
cfg.blescantime / float(100));
|
||||||
|
#ifdef BLECOUNTER
|
||||||
|
// stop & restart BLE scan task to apply new parameter
|
||||||
|
if (cfg.blescan) {
|
||||||
|
stop_BLEscan();
|
||||||
|
start_BLEscan();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_countmode(uint8_t val) {
|
void set_countmode(uint8_t val) {
|
||||||
@ -114,16 +181,36 @@ void set_countmode(uint8_t val) {
|
|||||||
void set_screensaver(uint8_t val) {
|
void set_screensaver(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: set screen saver to %s ", val ? "on" : "off");
|
ESP_LOGI(TAG, "Remote command: set screen saver to %s ", val ? "on" : "off");
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 1: cfg.screensaver = val; break;
|
case 1:
|
||||||
default: cfg.screensaver = 0; break;
|
cfg.screensaver = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cfg.screensaver = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_display(uint8_t val) {
|
void set_display(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: set screen to %s", val ? "on" : "off");
|
ESP_LOGI(TAG, "Remote command: set screen to %s", val ? "on" : "off");
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 1: cfg.screenon = val; break;
|
case 1:
|
||||||
default: cfg.screenon = 0; break;
|
cfg.screenon = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cfg.screenon = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_gps(uint8_t val) {
|
||||||
|
ESP_LOGI(TAG, "Remote command: set GPS to %s", val ? "on" : "off");
|
||||||
|
switch (val) {
|
||||||
|
case 1:
|
||||||
|
cfg.gpsmode = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cfg.gpsmode = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,47 +222,67 @@ void set_lorasf(uint8_t val) {
|
|||||||
void set_loraadr(uint8_t val) {
|
void set_loraadr(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: set LoRa ADR mode to %s", val ? "on" : "off");
|
ESP_LOGI(TAG, "Remote command: set LoRa ADR mode to %s", val ? "on" : "off");
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 1: cfg.adrmode = val; break;
|
case 1:
|
||||||
default: cfg.adrmode = 0; break;
|
cfg.adrmode = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cfg.adrmode = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
LMIC_setAdrMode(cfg.adrmode);
|
LMIC_setAdrMode(cfg.adrmode);
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_blescan(uint8_t val) {
|
void set_blescan(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: set BLE scan mode to %s", val ? "on" : "off");
|
ESP_LOGI(TAG, "Remote command: set BLE scanner to %s", val ? "on" : "off");
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 0:
|
case 0:
|
||||||
cfg.blescan = 0;
|
cfg.blescan = 0;
|
||||||
macs_ble = 0; // clear BLE counter
|
macs_ble = 0; // clear BLE counter
|
||||||
|
#ifdef BLECOUNTER
|
||||||
|
stop_BLEscan();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cfg.blescan = 1;
|
cfg.blescan = 1;
|
||||||
|
#ifdef BLECOUNTER
|
||||||
|
start_BLEscan();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_wifiant(uint8_t val) {
|
void set_wifiant(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: set Wifi antenna to %s", val ? "external" : "internal");
|
ESP_LOGI(TAG, "Remote command: set Wifi antenna to %s",
|
||||||
|
val ? "external" : "internal");
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 1: cfg.wifiant = val; break;
|
case 1:
|
||||||
default: cfg.wifiant = 0; break;
|
cfg.wifiant = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cfg.wifiant = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#ifdef HAS_ANTENNA_SWITCH
|
#ifdef HAS_ANTENNA_SWITCH
|
||||||
antenna_select(cfg.wifiant);
|
antenna_select(cfg.wifiant);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_vendorfilter(uint8_t val) {
|
void set_vendorfilter(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: set vendorfilter mode to %s", val ? "on" : "off");
|
ESP_LOGI(TAG, "Remote command: set vendorfilter mode to %s",
|
||||||
|
val ? "on" : "off");
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 1: cfg.vendorfilter = val; break;
|
case 1:
|
||||||
default: cfg.vendorfilter = 0; break;
|
cfg.vendorfilter = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cfg.vendorfilter = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_rgblum(uint8_t val) {
|
void set_rgblum(uint8_t val) {
|
||||||
// Avoid wrong parameters
|
// Avoid wrong parameters
|
||||||
cfg.rgblum = (val>=0 && val<=100) ? (uint8_t) val : RGBLUMINOSITY;
|
cfg.rgblum = (val >= 0 && val <= 100) ? (uint8_t)val : RGBLUMINOSITY;
|
||||||
ESP_LOGI(TAG, "Remote command: set RGB Led luminosity %d", cfg.rgblum);
|
ESP_LOGI(TAG, "Remote command: set RGB Led luminosity %d", cfg.rgblum);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -184,78 +291,75 @@ void set_lorapower(uint8_t val) {
|
|||||||
switch_lora(cfg.lorasf, val);
|
switch_lora(cfg.lorasf, val);
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_noop (uint8_t val) {
|
void get_config(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: noop - doing nothing");
|
|
||||||
};
|
|
||||||
|
|
||||||
void get_config (uint8_t val) {
|
|
||||||
ESP_LOGI(TAG, "Remote command: get configuration");
|
ESP_LOGI(TAG, "Remote command: get configuration");
|
||||||
int size = sizeof(configData_t);
|
transmit((byte *)&cfg, sizeof(cfg));
|
||||||
// declare send buffer (char byte array)
|
|
||||||
unsigned char *sendData = new unsigned char[size];
|
|
||||||
// copy current configuration (struct) to send buffer
|
|
||||||
memcpy(sendData, &cfg, size);
|
|
||||||
LMIC_setTxData2(RCMDPORT, sendData, size-1, 0); // send data unconfirmed on RCMD Port
|
|
||||||
delete sendData; // free memory
|
|
||||||
ESP_LOGI(TAG, "%d bytes queued in send queue", size-1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void get_uptime (uint8_t val) {
|
void get_uptime(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: get uptime");
|
ESP_LOGI(TAG, "Remote command: get uptime");
|
||||||
int size = sizeof(uptimecounter);
|
transmit((byte *)&uptimecounter, sizeof(uptimecounter));
|
||||||
unsigned char *sendData = new unsigned char[size];
|
|
||||||
memcpy(sendData, (unsigned char*)&uptimecounter , size);
|
|
||||||
LMIC_setTxData2(RCMDPORT, sendData, size-1, 0); // send data unconfirmed on RCMD Port
|
|
||||||
delete sendData; // free memory
|
|
||||||
ESP_LOGI(TAG, "%d bytes queued in send queue", size-1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void get_cputemp (uint8_t val) {
|
void get_cputemp(uint8_t val) {
|
||||||
ESP_LOGI(TAG, "Remote command: get cpu temperature");
|
ESP_LOGI(TAG, "Remote command: get cpu temperature");
|
||||||
float temp = temperatureRead();
|
float temp = temperatureRead();
|
||||||
int size = sizeof(temp);
|
transmit((byte *)&temp, sizeof(temp));
|
||||||
unsigned char *sendData = new unsigned char[size];
|
};
|
||||||
memcpy(sendData, (unsigned char*)&temp, size);
|
|
||||||
LMIC_setTxData2(RCMDPORT, sendData, size-1, 0); // send data unconfirmed on RCMD Port
|
void get_voltage(uint8_t val) {
|
||||||
delete sendData; // free memory
|
ESP_LOGI(TAG, "Remote command: get battery voltage");
|
||||||
ESP_LOGI(TAG, "%d bytes queued in send queue", size-1);
|
#ifdef HAS_BATTERY_PROBE
|
||||||
|
uint16_t voltage = read_voltage();
|
||||||
|
#else
|
||||||
|
uint16_t voltage = 0;
|
||||||
|
#endif
|
||||||
|
transmit((byte *)&voltage, sizeof(voltage));
|
||||||
|
};
|
||||||
|
|
||||||
|
void get_gps(uint8_t val) {
|
||||||
|
ESP_LOGI(TAG, "Remote command: get gps status");
|
||||||
|
#ifdef HAS_GPS
|
||||||
|
gps_read();
|
||||||
|
transmit((byte *)&gps_status, sizeof(gps_status));
|
||||||
|
ESP_LOGI(TAG, "lat=%f / lon=%f | Sats=%u | HDOP=%u | Alti=%u",
|
||||||
|
gps_status.latitude / 1000000, gps_status.longitude / 1000000,
|
||||||
|
gps_status.satellites, gps_status.hdop, gps_status.altitude);
|
||||||
|
#else
|
||||||
|
ESP_LOGE(TAG, "GPS not present");
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// assign previously defined functions to set of numeric remote commands
|
// assign previously defined functions to set of numeric remote commands
|
||||||
// format: opcode, function, flag (1 = do make settings persistent / 0 = don't)
|
// format: opcode, function, flag (1 = do make settings persistent / 0 = don't)
|
||||||
//
|
//
|
||||||
cmd_t table[] = {
|
cmd_t table[] = {{0x01, set_rssi, true}, {0x02, set_countmode, true},
|
||||||
{0x01, set_rssi, true},
|
{0x03, set_gps, true}, {0x04, set_display, true},
|
||||||
{0x02, set_countmode, true},
|
{0x05, set_lorasf, true}, {0x06, set_lorapower, true},
|
||||||
{0x03, set_noop, false},
|
{0x07, set_loraadr, true}, {0x08, set_screensaver, true},
|
||||||
{0x04, set_display, true},
|
{0x09, set_reset, false}, {0x0a, set_sendcycle, true},
|
||||||
{0x05, set_lorasf, true},
|
{0x0b, set_wifichancycle, true}, {0x0c, set_blescantime, true},
|
||||||
{0x06, set_lorapower, true},
|
{0x0d, set_vendorfilter, false}, {0x0e, set_blescan, true},
|
||||||
{0x07, set_loraadr, true},
|
{0x0f, set_wifiant, true}, {0x10, set_rgblum, true},
|
||||||
{0x08, set_screensaver, true},
|
{0x80, get_config, false}, {0x81, get_uptime, false},
|
||||||
{0x09, set_reset, false},
|
{0x82, get_cputemp, false}, {0x83, get_voltage, false},
|
||||||
{0x0a, set_sendcycle, true},
|
{0x84, get_gps, false}};
|
||||||
{0x0b, set_wifichancycle, true},
|
|
||||||
{0x0c, set_blescantime, true},
|
|
||||||
{0x0d, set_vendorfilter, false},
|
|
||||||
{0x0e, set_blescan, true},
|
|
||||||
{0x0f, set_wifiant, true},
|
|
||||||
{0x10, set_rgblum, true},
|
|
||||||
{0x80, get_config, false},
|
|
||||||
{0x81, get_uptime, false},
|
|
||||||
{0x82, get_cputemp, false}
|
|
||||||
};
|
|
||||||
|
|
||||||
// check and execute remote command
|
// check and execute remote command
|
||||||
void rcommand(uint8_t cmd, uint8_t arg) {
|
void rcommand(uint8_t cmd, uint8_t arg) {
|
||||||
int i = sizeof(table) / sizeof(table[0]); // number of commands in command table
|
int i =
|
||||||
|
sizeof(table) / sizeof(table[0]); // number of commands in command table
|
||||||
bool store_flag = false;
|
bool store_flag = false;
|
||||||
while(i--) {
|
while (i--) {
|
||||||
if(cmd == table[i].nam) { // check if valid command
|
if (cmd == table[i].nam) { // check if valid command
|
||||||
table[i].func(arg); // then execute assigned function
|
table[i].func(arg); // then execute assigned function
|
||||||
if ( table[i].store ) store_flag = true; // set save flag if function needs to store configuration
|
if (table[i].store)
|
||||||
|
store_flag =
|
||||||
|
true; // set save flag if function needs to store configuration
|
||||||
break; // exit check loop, since command was found
|
break; // exit check loop, since command was found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (store_flag) saveConfig(); // if save flag is set: store new configuration in NVS to make it persistent
|
if (store_flag)
|
||||||
|
saveConfig(); // if save flag is set: store new configuration in NVS to make
|
||||||
|
// it persistent
|
||||||
}
|
}
|
@ -6,8 +6,7 @@
|
|||||||
// RGB Led instance
|
// RGB Led instance
|
||||||
SmartLed rgb_led(LED_WS2812, 1, HAS_RGB_LED);
|
SmartLed rgb_led(LED_WS2812, 1, HAS_RGB_LED);
|
||||||
|
|
||||||
float rgb_CalcColor(float p, float q, float t)
|
float rgb_CalcColor(float p, float q, float t) {
|
||||||
{
|
|
||||||
if (t < 0.0f)
|
if (t < 0.0f)
|
||||||
t += 1.0f;
|
t += 1.0f;
|
||||||
if (t > 1.0f)
|
if (t > 1.0f)
|
||||||
@ -30,19 +29,15 @@ float rgb_CalcColor(float p, float q, float t)
|
|||||||
// HslColor using H, S, L values (0.0 - 1.0)
|
// HslColor using H, S, L values (0.0 - 1.0)
|
||||||
// L should be limited to between (0.0 - 0.5)
|
// L should be limited to between (0.0 - 0.5)
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
RGBColor rgb_hsl2rgb(float h, float s, float l)
|
RGBColor rgb_hsl2rgb(float h, float s, float l) {
|
||||||
{
|
|
||||||
RGBColor RGB_color;
|
RGBColor RGB_color;
|
||||||
float r;
|
float r;
|
||||||
float g;
|
float g;
|
||||||
float b;
|
float b;
|
||||||
|
|
||||||
if (s == 0.0f || l == 0.0f)
|
if (s == 0.0f || l == 0.0f) {
|
||||||
{
|
|
||||||
r = g = b = l; // achromatic or black
|
r = g = b = l; // achromatic or black
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s);
|
float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s);
|
||||||
float p = 2.0f * l - q;
|
float p = 2.0f * l - q;
|
||||||
r = rgb_CalcColor(p, q, h + 1.0f / 3.0f);
|
r = rgb_CalcColor(p, q, h + 1.0f / 3.0f);
|
||||||
@ -60,15 +55,15 @@ RGBColor rgb_hsl2rgb(float h, float s, float l)
|
|||||||
void rgb_set_color(uint16_t hue) {
|
void rgb_set_color(uint16_t hue) {
|
||||||
if (hue == COLOR_NONE) {
|
if (hue == COLOR_NONE) {
|
||||||
// Off
|
// Off
|
||||||
rgb_led[0] = Rgb(0,0,0);
|
rgb_led[0] = Rgb(0, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
// see http://www.workwithcolor.com/blue-color-hue-range-01.htm
|
// see http://www.workwithcolor.com/blue-color-hue-range-01.htm
|
||||||
// H (is color from 0..360) should be between 0.0 and 1.0
|
// H (is color from 0..360) should be between 0.0 and 1.0
|
||||||
// S is saturation keep it to 1
|
// S is saturation keep it to 1
|
||||||
// L is brightness should be between 0.0 and 0.5
|
// L is brightness should be between 0.0 and 0.5
|
||||||
// cfg.rgblum is between 0 and 100 (percent)
|
// cfg.rgblum is between 0 and 100 (percent)
|
||||||
RGBColor target = rgb_hsl2rgb( hue / 360.0f, 1.0f, 0.005f * cfg.rgblum);
|
RGBColor target = rgb_hsl2rgb(hue / 360.0f, 1.0f, 0.005f * cfg.rgblum);
|
||||||
//uint32_t color = target.R<<16 | target.G<<8 | target.B;
|
// uint32_t color = target.R<<16 | target.G<<8 | target.B;
|
||||||
rgb_led[0] = Rgb(target.R, target.G, target.B);
|
rgb_led[0] = Rgb(target.R, target.G, target.B);
|
||||||
}
|
}
|
||||||
// Show
|
// Show
|
||||||
|
@ -19,8 +19,7 @@
|
|||||||
#define COLOR_WHITE 360
|
#define COLOR_WHITE 360
|
||||||
#define COLOR_NONE 999
|
#define COLOR_NONE 999
|
||||||
|
|
||||||
struct RGBColor
|
struct RGBColor {
|
||||||
{
|
|
||||||
uint8_t R;
|
uint8_t R;
|
||||||
uint8_t G;
|
uint8_t G;
|
||||||
uint8_t B;
|
uint8_t B;
|
||||||
|
@ -36,37 +36,41 @@
|
|||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
uint32_t rokkit(const char * data, int len) {
|
uint32_t rokkit(const char *data, int len) {
|
||||||
uint32_t hash, tmp;
|
uint32_t hash, tmp;
|
||||||
int rem;
|
int rem;
|
||||||
|
|
||||||
if (len <= 0 || data == 0) return 0;
|
if (len <= 0 || data == 0)
|
||||||
|
return 0;
|
||||||
hash = len;
|
hash = len;
|
||||||
rem = len & 3;
|
rem = len & 3;
|
||||||
len >>= 2;
|
len >>= 2;
|
||||||
|
|
||||||
/* Main loop */
|
/* Main loop */
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
hash += *((uint16_t*)data);
|
hash += *((uint16_t *)data);
|
||||||
tmp = (*((uint16_t*)(data+2)) << 11) ^ hash;
|
tmp = (*((uint16_t *)(data + 2)) << 11) ^ hash;
|
||||||
hash = (hash << 16) ^ tmp;
|
hash = (hash << 16) ^ tmp;
|
||||||
data += 2*2;
|
data += 2 * 2;
|
||||||
hash += hash >> 11;
|
hash += hash >> 11;
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle end cases */
|
/* Handle end cases */
|
||||||
switch (rem) {
|
switch (rem) {
|
||||||
case 3: hash += *((uint16_t*)data);
|
case 3:
|
||||||
|
hash += *((uint16_t *)data);
|
||||||
hash ^= hash << 16;
|
hash ^= hash << 16;
|
||||||
hash ^= ((signed char)data[2]) << 18;
|
hash ^= ((signed char)data[2]) << 18;
|
||||||
hash += hash >> 11;
|
hash += hash >> 11;
|
||||||
break;
|
break;
|
||||||
case 2: hash += *((uint16_t*)data);
|
case 2:
|
||||||
|
hash += *((uint16_t *)data);
|
||||||
hash ^= hash << 11;
|
hash ^= hash << 11;
|
||||||
hash += hash >> 17;
|
hash += hash >> 17;
|
||||||
break;
|
break;
|
||||||
case 1: hash += (signed char)*data;
|
case 1:
|
||||||
|
hash += (signed char)*data;
|
||||||
hash ^= hash << 10;
|
hash ^= hash << 10;
|
||||||
hash += hash >> 1;
|
hash += hash >> 1;
|
||||||
}
|
}
|
||||||
|
1639
src/vendor_array.h
1639
src/vendor_array.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user