Initial upload
This commit is contained in:
parent
c2db6ee4b6
commit
f238dc3f0f
270
LICENSE
270
LICENSE
@ -1,4 +1,52 @@
|
||||
Apache License
|
||||
LICENSE
|
||||
|
||||
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
|
||||
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
NOTICE:
|
||||
Parts of the source files in this repository are made available under different licenses,
|
||||
listed below. Refer to each individual source file for more details.
|
||||
|
||||
------------------------------------------------------------------------------------------------
|
||||
antenna.cpp
|
||||
|
||||
Parts of antenna.cpp were derived or taken from
|
||||
|
||||
https://github.com/pycom/pycom-micropython-sigfox/blob/master/esp32/util/antenna.c
|
||||
|
||||
under this Licence:
|
||||
|
||||
Copyright (c) 2016, Pycom Limited.
|
||||
|
||||
This software is licensed under the GNU GPL version 3 or any
|
||||
later version, with permitted additional terms. For more information
|
||||
see the Pycom Licence v1.0 document supplied with this file, or
|
||||
available at https://www.pycom.io/opensource/licensing
|
||||
|
||||
------------------------------------------------------------------------------------------------
|
||||
wifisniffer.cpp
|
||||
|
||||
Parts of wifisniffer.cpp were derived or taken from
|
||||
|
||||
* Copyright (c) 2017, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
|
||||
* ESP32/016 WiFi Sniffer
|
||||
* https://github.com/lpodkalicki/blog/tree/master/esp32/016_wifi_sniffer
|
||||
|
||||
under this License:
|
||||
|
||||
" Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
@ -173,29 +221,209 @@
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS"
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
------------------------------------------------------------------------------------------------
|
||||
src/lorawan.cpp and /lib/arduino-lmic-1.5.0-<...>
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
Parts of lorawan.cpp, and the arduino lmic library, which is included in the /lib directory of this
|
||||
repository, were derived or taken from
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Arduino-LMIC Library
|
||||
TTN OTAA Example
|
||||
https://github.com/matthijskooijman/arduino-lmic/blob/master/examples/ttn-otaa/
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
under this Licence:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
"License
|
||||
Most source files in this repository are made available under the Eclipse Public License v1.0. The examples which use a more liberal license. Some of the AES code is available under the LGPL. Refer to each individual source file for more details."
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
------------------------------------------------------------------------------------------------
|
||||
blecount.cpp
|
||||
|
||||
Parts of blecount.cpp were derived or taken from
|
||||
|
||||
nkolban esp32 snippets
|
||||
BLE Scan
|
||||
https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils/tests/BLETests/Arduino/BLE_scan
|
||||
|
||||
under this Licence:
|
||||
|
||||
" Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS"
|
||||
|
||||
------------------------------------------------------------------------------------------------
|
||||
|
165
README.md
Normal file
165
README.md
Normal file
@ -0,0 +1,165 @@
|
||||
# Paxcounter
|
||||
Wifi & Bluetooth driven, LoRaWAN enabled, battery powered mini ESP32 Paxcounter
|
||||
built on cheap ESP32 boards
|
||||
|
||||
<img src="img/Paxcounter_GIF.gif">
|
||||
|
||||
Check out Wiki in this git repo for additional information on suitable hardware:
|
||||
https://github.com/cyberman54/Paxcounter/wiki
|
||||
|
||||
# Hardware
|
||||
|
||||
Currently supported IoT boards:
|
||||
- Heltec LoRa-32
|
||||
- TTGOv2
|
||||
- Pycom LoPy
|
||||
- Pycom LoPy4
|
||||
|
||||
Target platform must be selected in [platformio.ini](https://github.com/cyberman54/Paxcounter/blob/master/platformio.ini).
|
||||
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory.
|
||||
|
||||
# Building
|
||||
|
||||
Use <A HREF="https://platformio.org/">PlatformIO</A> with your preferred IDE for development and building this code.
|
||||
|
||||
Before compiling the code, create file loraconf.h in the /src directory from the template [loraconf.sample.h](https://github.com/cyberman54/Paxcounter/blob/master/src/loraconf.sample.h) and populate it with your personal APPEUI und APPKEY for the LoRaWAN network. Only OTAA join is supported, not ABP. The DEVEUI will be derived from the device's MAC adress during device startup and is shown as well on the device's display (if it has one) as on the serial console for copying it to your LoRaWAN network server settings. If you enter a DEVEUI in loraconf.h it will be used instead.
|
||||
|
||||
# Legal note
|
||||
|
||||
**Depending on your country's laws it may be illegal to sniff wireless networks for MAC addresses. Please check and respect your country's laws before using this code!**
|
||||
|
||||
(e.g. US citizens check [Section 18 U.S. Code § 2511](https://www.law.cornell.edu/uscode/text/18/2511) and [discussion](https://github.com/schollz/howmanypeoplearearound/issues/4) on this)
|
||||
|
||||
(e.g. UK citizens check [Data Protection Act 1998](https://ico.org.uk/media/1560691/wi-fi-location-analytics-guidance.pdf) and [this case](https://www.cbsnews.com/news/uk-bars-trash-cans-from-tracking-people-with-wi-fi/))
|
||||
|
||||
Disclosure: The Paxcounter code stores scanned MAC adresses in the device's RAM, and keeps it in RAM temporary for a configurable scan cycle time (default 240 seconds). After each scan cycle the collected MAC data is erased from RAM. MAC data never is transferred to the LoRaWAN network. No kind of tracking and no persistent storing of MAC data or timestamps on the device and no other kind of analytics than counting is 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 made visible and scanned by this code. The same applies to Bluetooth MACs, if the bluetooth option in the code is enabled.
|
||||
|
||||
# Payload format description
|
||||
|
||||
FPort1:
|
||||
|
||||
byte 1: 16-bit Wifi counter, MSB
|
||||
byte 2: 16-bit Wifi counter, LSB
|
||||
byte 3: 16-bit BLE counter, MSB
|
||||
byte 4: 16-bit BLE counter, LSB
|
||||
|
||||
FPort2:
|
||||
|
||||
see remote command set
|
||||
|
||||
# Remote command set
|
||||
|
||||
The device listenes for remote control commands on LoRaWAN Port 2.
|
||||
Each command is followed by exactly one parameter.
|
||||
Multiple command/parameter pairs can be concatenated and sent in one single payload downlink.
|
||||
|
||||
Note: all settings are stored in NVRAM and will be reloaded when device starts. To reset device to factory settings press button (if device has one), or send remote command 09 02 09 00 unconfirmed(!) once.
|
||||
|
||||
0x01 set Wifi scan RSSI limit
|
||||
|
||||
1 ... 255 used for wifi scan radius (greater values increase wifi scan radius, values 50...110 make sense)
|
||||
0 = Wifi rssi limiter disabled [default]
|
||||
|
||||
0x02 set counter mode
|
||||
|
||||
0 = cyclic unconfirmed, mac counter reset after each wifi scan cycle, data is sent only once [default]
|
||||
1 = cumulative counter, mac counter is never reset
|
||||
2 = cyclic confirmed, like 0 but data is resent until confirmation by network received
|
||||
|
||||
0x03 set screen saver mode
|
||||
|
||||
0 = screen saver off [default]
|
||||
1 = screen saver on
|
||||
|
||||
0x04 set display on/off
|
||||
|
||||
0 = display off
|
||||
1 = display on [default]
|
||||
|
||||
0x05 set LoRa spread factor
|
||||
|
||||
7 ... 12 [default: 9]
|
||||
|
||||
0x06 set LoRa TXpower
|
||||
|
||||
2 ... 15 [default: 15]
|
||||
|
||||
0x07 set LoRa Adaptive Data Rate mode
|
||||
|
||||
0 = ADR off
|
||||
1 = ADR on [default]
|
||||
|
||||
note: set ADR to off, if device is moving, set to on, if not.
|
||||
|
||||
0x08 do nothing
|
||||
|
||||
useful to clear pending commands from LoRaWAN server quere, or to check RSSI on device
|
||||
|
||||
0x09 reset functions
|
||||
|
||||
0 = restart device
|
||||
1 = reset MAC counter to zero
|
||||
2 = reset device to factory settings
|
||||
|
||||
0x0A set Wifi scan cycle timer
|
||||
|
||||
0 ... 255 duration of a wifi scan cycle in seconds/2
|
||||
e.g. 120 -> 1 cycle runs for 240 seconds
|
||||
|
||||
0x0B set Wifi channel switch interval timer
|
||||
|
||||
0 ... 255 timeout for scanning 1 wifi channel in seconds/100
|
||||
e.g. 50 -> each channel is scanned for 0,5 seconds
|
||||
|
||||
0x0C set BLE scan cycle timer
|
||||
|
||||
0 ... 255 duration of a BLE scan cycle in seconds
|
||||
e.g. 30 -> 1 cycle runs for 30 seconds
|
||||
|
||||
0x0D set BLE scan mode
|
||||
|
||||
0 = disabled [default]
|
||||
1 = enabled
|
||||
|
||||
0x80 get device configuration
|
||||
|
||||
device answers with it's current configuration:
|
||||
|
||||
byte 1: Lora SF (7..12)
|
||||
byte 2: Lora TXpower (2..15)
|
||||
byte 3: Lora ADR (1=on, 0=off)
|
||||
byte 4: Screensaver status (1=on, 0=off)
|
||||
byte 5: Display status (1=on, 0=off)
|
||||
byte 6: Counter mode (0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed)
|
||||
bytes 7-8: RSSI limiter threshold value (negative)
|
||||
byte 9: Wifi scan cycle duration in seconds/2 (0..255)
|
||||
byte 10: Wifi channel switch interval in seconds/100 (0..255)
|
||||
byte 11: BLE scan cycle duration in seconds (0..255)
|
||||
byte 12: BLE scan mode (1=on, 0=0ff)
|
||||
bytes 13-22: Software version (ASCII format)
|
||||
|
||||
0x81 get device uptime
|
||||
|
||||
bytes 1-7: Uptime in seconds (little endian format)
|
||||
|
||||
# License
|
||||
|
||||
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
|
||||
|
||||
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
NOTICE:
|
||||
Parts of the source files in this repository are made available under different licenses,
|
||||
see file <A HREF="https://github.com/cyberman54/Paxcounter/blob/master/LICENSE">LICENSE.txt</A> in this repository. Refer to each individual source file for more details.
|
BIN
img/Paxcounter_GIF.gif
Normal file
BIN
img/Paxcounter_GIF.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 MiB |
BIN
img/foto_no_exif.jpg
Normal file
BIN
img/foto_no_exif.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 MiB |
365
lib/arduino-lmic-1.5.0-arduino-2-tweaked/README.md
Normal file
365
lib/arduino-lmic-1.5.0-arduino-2-tweaked/README.md
Normal file
@ -0,0 +1,365 @@
|
||||
Arduino-LMIC library
|
||||
====================
|
||||
This repository contains the IBM LMIC (LoraMAC-in-C) library, slightly
|
||||
modified to run in the Arduino environment, allowing using the SX1272,
|
||||
SX1276 tranceivers and compatible modules (such as some HopeRF RFM9x
|
||||
modules).
|
||||
|
||||
This library mostly exposes the functions defined by LMIC, it makes no
|
||||
attempt to wrap them in a higher level API that is more in the Arduino
|
||||
style. To find out how to use the library itself, see the examples, or
|
||||
see the PDF file in the doc subdirectory.
|
||||
|
||||
This library requires Arduino IDE version 1.6.6 or above, since it
|
||||
requires C99 mode to be enabled by default.
|
||||
|
||||
Installing
|
||||
----------
|
||||
To install this library:
|
||||
|
||||
- install it using the Arduino Library manager ("Sketch" -> "Include
|
||||
Library" -> "Manage Libraries..."), or
|
||||
- download a zipfile from github using the "Download ZIP" button and
|
||||
install it using the IDE ("Sketch" -> "Include Library" -> "Add .ZIP
|
||||
Library..."
|
||||
- clone this git repository into your sketchbook/libraries folder.
|
||||
|
||||
For more info, see https://www.arduino.cc/en/Guide/Libraries
|
||||
|
||||
Features
|
||||
--------
|
||||
The LMIC library provides a fairly complete LoRaWAN Class A and Class B
|
||||
implementation, supporting the EU-868 and US-915 bands. Only a limited
|
||||
number of features was tested using this port on Arduino hardware, so be
|
||||
careful when using any of the untested features.
|
||||
|
||||
What certainly works:
|
||||
- Sending packets uplink, taking into account duty cycling.
|
||||
- Encryption and message integrity checking.
|
||||
- Receiving downlink packets in the RX2 window.
|
||||
- Custom frequencies and datarate settings.
|
||||
- Over-the-air activation (OTAA / joining).
|
||||
|
||||
What has not been tested:
|
||||
- Receiving downlink packets in the RX1 window.
|
||||
- Receiving and processing MAC commands.
|
||||
- Class B operation.
|
||||
|
||||
If you try one of these untested features and it works, be sure to let
|
||||
us know (creating a github issue is probably the best way for that).
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
A number of features can be configured or disabled by editing the
|
||||
`config.h` file in the library folder. Unfortunately the Arduino
|
||||
environment does not offer any way to do this (compile-time)
|
||||
configuration from the sketch, so be careful to recheck your
|
||||
configuration when you switch between sketches or update the library.
|
||||
|
||||
At the very least, you should set the right type of transceiver (SX1272
|
||||
vs SX1276) in config.h, most other values should be fine at their
|
||||
defaults.
|
||||
|
||||
Supported hardware
|
||||
------------------
|
||||
This library is intended to be used with plain LoRa transceivers,
|
||||
connecting to them using SPI. In particular, the SX1272 and SX1276
|
||||
families are supported (which should include SX1273, SX1277, SX1278 and
|
||||
SX1279 which only differ in the available frequencies, bandwidths and
|
||||
spreading factors). It has been tested with both SX1272 and SX1276
|
||||
chips, using the Semtech SX1272 evaluation board and the HopeRF RFM92
|
||||
and RFM95 boards (which supposedly contain an SX1272 and SX1276 chip
|
||||
respectively).
|
||||
|
||||
This library contains a full LoRaWAN stack and is intended to drive
|
||||
these Transceivers directly. It is *not* intended to be used with
|
||||
full-stack devices like the Microchip RN2483 and the Embit LR1272E.
|
||||
These contain a transceiver and microcontroller that implements the
|
||||
LoRaWAN stack and exposes a high-level serial interface instead of the
|
||||
low-level SPI transceiver interface.
|
||||
|
||||
This library is intended to be used inside the Arduino environment. It
|
||||
should be architecture-independent, so it should run on "normal" AVR
|
||||
arduinos, but also on the ARM-based ones, and some success has been seen
|
||||
running on the ESP8266 board as well. It was tested on the Arduino Uno,
|
||||
Pinoccio Scout, Teensy LC and 3.x, ESP8266, Arduino 101.
|
||||
|
||||
This library an be quite heavy, especially if the fairly small ATmega
|
||||
328p (such as in the Arduino Uno) is used. In the default configuration,
|
||||
the available 32K flash space is nearly filled up (this includes some
|
||||
debug output overhead, though). By disabling some features in `config.h`
|
||||
(like beacon tracking and ping slots, which are not typically needed),
|
||||
some space can be freed up. Some work is underway to replace the AES
|
||||
encryption implementation, which should free up another 8K or so of
|
||||
flash in the future, making this library feasible to run on a 328p
|
||||
microcontroller.
|
||||
|
||||
Connections
|
||||
-----------
|
||||
To make this library work, your Arduino (or whatever Arduino-compatible
|
||||
board you are using) should be connected to the transceiver. The exact
|
||||
connections are a bit dependent on the transceiver board and Arduino
|
||||
used, so this section tries to explain what each connection is for and
|
||||
in what cases it is (not) required.
|
||||
|
||||
Note that the SX1272 module runs at 3.3V and likely does not like 5V on
|
||||
its pins (though the datasheet is not say anything about this, and my
|
||||
transceiver did not obviously break after accidentally using 5V I/O for
|
||||
a few hours). To be safe, make sure to use a level shifter, or an
|
||||
Arduino running at 3.3V. The Semtech evaluation board has 100 ohm resistors in
|
||||
series with all data lines that might prevent damage, but I would not
|
||||
count on that.
|
||||
|
||||
### Power
|
||||
The SX127x transceivers need a supply voltage between 1.8V and 3.9V.
|
||||
Using a 3.3V supply is typical. Some modules have a single power pin
|
||||
(like the HopeRF modules, labeled 3.3V) but others expose multiple power
|
||||
pins for different parts (like the Semtech evaluation board that has
|
||||
`VDD_RF`, `VDD_ANA` and `VDD_FEM`), which can all be connected together.
|
||||
Any *GND* pins need to be connected to the Arduino *GND* pin(s).
|
||||
|
||||
### SPI
|
||||
The primary way of communicating with the transceiver is through SPI
|
||||
(Serial Peripheral Interface). This uses four pins: MOSI, MISO, SCK and
|
||||
SS. The former three need to be directly connected: so MOSI to MOSI,
|
||||
MISO to MISO, SCK to SCK. Where these pins are located on your Arduino
|
||||
varies, see for example the "Connections" section of the [Arduino SPI
|
||||
documentation](SPI).
|
||||
|
||||
The SS (slave select) connection is a bit more flexible. On the SPI
|
||||
slave side (the transceiver), this must be connect to the pin
|
||||
(typically) labeled *NSS*. On the SPI master (Arduino) side, this pin
|
||||
can connect to any I/O pin. Most Arduinos also have a pin labeled "SS",
|
||||
but this is only relevant when the Arduino works as an SPI slave, which
|
||||
is not the case here. Whatever pin you pick, you need to tell the
|
||||
library what pin you used through the pin mapping (see below).
|
||||
|
||||
[SPI]: https://www.arduino.cc/en/Reference/SPI
|
||||
|
||||
### DIO pins
|
||||
The DIO (digitial I/O) pins on the transceiver board can be configured
|
||||
for various functions. The LMIC library uses them to get instant status
|
||||
information from the transceiver. For example, when a LoRa transmission
|
||||
starts, the DIO0 pin is configured as a TxDone output. When the
|
||||
transmission is complete, the DIO0 pin is made high by the transceiver,
|
||||
which can be detected by the LMIC library.
|
||||
|
||||
The LMIC library needs only access to DIO0, DIO1 and DIO2, the other
|
||||
DIOx pins can be left disconnected. On the Arduino side, they can
|
||||
connect to any I/O pin, since the current implementation does not use
|
||||
interrupts or other special hardware features (though this might be
|
||||
added in the feature, see also the "Timing" section).
|
||||
|
||||
In LoRa mode the DIO pins are used as follows:
|
||||
* DIO0: TxDone and RxDone
|
||||
* DIO1: RxTimeout
|
||||
|
||||
In FSK mode they are used as follows::
|
||||
* DIO0: PayloadReady and PacketSent
|
||||
* DIO2: TimeOut
|
||||
|
||||
Both modes need only 2 pins, but the tranceiver does not allow mapping
|
||||
them in such a way that all needed interrupts map to the same 2 pins.
|
||||
So, if both LoRa and FSK modes are used, all three pins must be
|
||||
connected.
|
||||
|
||||
The pins used on the Arduino side should be configured in the pin
|
||||
mapping in your sketch (see below).
|
||||
|
||||
### Reset
|
||||
The transceiver has a reset pin that can be used to explicitely reset
|
||||
it. The LMIC library uses this to ensure the chip is in a consistent
|
||||
state at startup. In practice, this pin can be left disconnected, since
|
||||
the transceiver will already be in a sane state on power-on, but
|
||||
connecting it might prevent problems in some cases.
|
||||
|
||||
On the Arduino side, any I/O pin can be used. The pin number used must
|
||||
be configured in the pin mapping (see below).
|
||||
|
||||
### RXTX
|
||||
The transceiver contains two separate antenna connections: One for RX
|
||||
and one for TX. A typical transceiver board contains an antenna switch
|
||||
chip, that allows switching a single antenna between these RX and TX
|
||||
connections. Such a antenna switcher can typically be told what
|
||||
position it should be through an input pin, often labeled *RXTX*.
|
||||
|
||||
The easiest way to control the antenna switch is to use the *RXTX* pin
|
||||
on the SX127x transceiver. This pin is automatically set high during TX
|
||||
and low during RX. For example, the HopeRF boards seem to have this
|
||||
connection in place, so they do not expose any *RXTX* pins and the pin
|
||||
can be marked as unused in the pin mapping.
|
||||
|
||||
Some boards do expose the antenna switcher pin, and sometimes also the
|
||||
SX127x *RXTX* pin. For example, the SX1272 evaluation board calls the
|
||||
former *FEM_CTX* and the latter *RXTX*. Again, simply connecting these
|
||||
together with a jumper wire is the easiest solution.
|
||||
|
||||
Alternatively, or if the SX127x *RXTX* pin is not available, LMIC can be
|
||||
configured to control the antenna switch. Connect the antenna switch
|
||||
control pin (e.g. *FEM_CTX* on the Semtech evaluation board) to any I/O
|
||||
pin on the Arduino side, and configure the pin used in the pin map (see
|
||||
below). It is not entirely clear why would *not* want the transceiver to
|
||||
control the antenna directly, though.
|
||||
|
||||
### Pin mapping
|
||||
As described above, most connections can use arbitrary I/O pins on the
|
||||
Arduino side. To tell the LMIC library about these, a pin mapping struct
|
||||
is used in the sketch file.
|
||||
|
||||
For example, this could look like this:
|
||||
|
||||
lmic_pinmap lmic_pins = {
|
||||
.nss = 6,
|
||||
.rxtx = LMIC_UNUSED_PIN,
|
||||
.rst = 5,
|
||||
.dio = {2, 3, 4},
|
||||
};
|
||||
|
||||
The names refer to the pins on the transceiver side, the numbers refer
|
||||
to the Arduino pin numbers (to use the analog pins, use constants like
|
||||
`A0`). For the DIO pins, the three numbers refer to DIO0, DIO1 and DIO2
|
||||
respectively. Any pins that are not needed should be specified as
|
||||
`LMIC_UNUSED_PIN`. The nss and dio0 pin is required, the others can
|
||||
potentially left out (depending on the environments and requirements,
|
||||
see the notes above for when a pin can or cannot be left out).
|
||||
|
||||
The name of this struct must always be `lmic_pins`, which is a special name
|
||||
recognized by the library.
|
||||
|
||||
#### LoRa Nexus by Ideetron
|
||||
This board uses the following pin mapping:
|
||||
|
||||
const lmic_pinmap lmic_pins = {
|
||||
.nss = 10,
|
||||
.rxtx = LMIC_UNUSED_PIN,
|
||||
.rst = LMIC_UNUSED_PIN, // hardwired to AtMega RESET
|
||||
.dio = {4, 5, 7},
|
||||
};
|
||||
|
||||
Examples
|
||||
--------
|
||||
This library currently provides three examples:
|
||||
|
||||
- `ttn-abp.ino` shows a basic transmission of a "Hello, world!" message
|
||||
using the LoRaWAN protocol. It contains some frequency settings and
|
||||
encryption keys intended for use with The Things Network, but these
|
||||
also correspond to the default settings of most gateways, so it
|
||||
should work with other networks and gateways as well. This example
|
||||
uses activation-by-personalization (ABP, preconfiguring a device
|
||||
address and encryption keys), and does not employ over-the-air
|
||||
activation.
|
||||
|
||||
Reception of packets (in response to transmission, using the RX1 and
|
||||
RX2 receive windows is also supported).
|
||||
|
||||
- `ttn-otaa.ino` also sends a "Hello, world!" message, but uses over
|
||||
the air activation (OTAA) to first join a network to establish a
|
||||
session and security keys. This was tested with The Things Network,
|
||||
but should also work (perhaps with some changes) for other networks.
|
||||
|
||||
- `raw.ino` shows how to access the radio on a somewhat low level,
|
||||
and allows to send raw (non-LoRaWAN) packets between nodes directly.
|
||||
This is useful to verify basic connectivity, and when no gateway is
|
||||
available, but this example also bypasses duty cycle checks, so be
|
||||
careful when changing the settings.
|
||||
|
||||
Timing
|
||||
------
|
||||
Unfortunately, the SX127x tranceivers do not support accurate
|
||||
timekeeping themselves (there is a sequencer that is *almost* sufficient
|
||||
for timing the RX1 and RX2 downlink windows, but that is only available
|
||||
in FSK mode, not in LoRa mode). This means that the microcontroller is
|
||||
responsible for keeping track of time. In particular, it should note
|
||||
when a packet finished transmitting, so it can open up the RX1 and RX2
|
||||
receive windows at a fixed time after the end of transmission.
|
||||
|
||||
This timing uses the Arduino `micros()` timer, which has a granularity
|
||||
of 4μs and is based on the primary microcontroller clock. For timing
|
||||
events, the tranceiver uses its DIOx pins as interrupt outputs. In the
|
||||
current implementation, these pins are not handled by an actual
|
||||
interrupt handler, but they are just polled once every LMIC loop,
|
||||
resulting in a bit inaccuracy in the timestamping. Also, running
|
||||
scheduled jobs (such as opening up the receive windows) is done using a
|
||||
polling approach, which might also result in further delays.
|
||||
|
||||
Fortunately, LoRa is a fairly slow protocol and the timing of the
|
||||
receive windows is not super critical. To synchronize transmitter and
|
||||
receiver, a preamble is first transmitted. Using LoRaWAN, this preamble
|
||||
consists of 8 symbols, of which the receiver needs to see 4 symbols to
|
||||
lock on. The current implementation tries to enable the receiver for 5
|
||||
symbol times at 1.5 symbol after the start of the receive window,
|
||||
meaning that a inacurracy of plus or minus 2.5 symbol times should be
|
||||
acceptable.
|
||||
|
||||
At the fastest LoRa setting supported by the tranceiver (SF5BW500) a
|
||||
single preamble symbol takes 64μs, so the receive window timing should
|
||||
be accurate within 160μs (for LoRaWAN this is SF7BW250, needing accuracy
|
||||
within 1280μs). This is certainly within a crystal's accuracy, but using
|
||||
the internal oscillator is probably not feasible (which is 1% - 10%
|
||||
accurate, depending on calibration). This accuracy should also be
|
||||
feasible with the polling approach used, provided that the LMIC loop is
|
||||
run often enough.
|
||||
|
||||
It would be good to properly review this code at some point, since it
|
||||
seems that in some places some offsets and corrections are applied that
|
||||
might not be appropriate for the Arduino environment. So if reception is
|
||||
not working, the timing is something to have a closer look at.
|
||||
|
||||
The LMIC library was intended to connect the DIO pins to interrupt
|
||||
lines and run code inside the interrupt handler. However, doing this
|
||||
opens up an entire can of worms with regard to doing SPI transfers
|
||||
inside interrupt routines (some of which is solved by the Arduino
|
||||
`beginTransaction()` API, but possibly not everything). One simpler
|
||||
alternative could be to use an interrupt handler to just store a
|
||||
timestamp, and then do the actual handling in the main loop (this
|
||||
requires modifications of the library to pass a timestamp to the LMIC
|
||||
`radio_irq_handler()` function).
|
||||
|
||||
An even more accurate solution could be to use a dedicated timer with an
|
||||
input capture unit, that can store the timestamp of a change on the DIO0
|
||||
pin (the only one that is timing-critical) entirely in hardware.
|
||||
Unfortunately, timer0, as used by Arduino's `millis()` and `micros()`
|
||||
functions does not seem to have an input capture unit, meaning a
|
||||
separate timer is needed for this.
|
||||
|
||||
If the main microcontroller does not have a crystal, but uses the
|
||||
internal oscillator, the clock output of the transceiver (on DIO5) could
|
||||
be usable to drive this timer instead of the main microcontroller clock,
|
||||
to ensure the receive window timing is sufficiently accurate. Ideally,
|
||||
this would use timer2, which supports asynchronous mode (e.g. running
|
||||
while the microcontroller is sleeping), but that timer does not have an
|
||||
input capture unit. Timer1 has one, but it seems it will stop running
|
||||
once the microcontroller sleeps. Running the microcontroller in idle
|
||||
mode with a slower clock might be feasible, though. Instead of using the
|
||||
main crystal oscillator of the transceiver, it could be possible to use
|
||||
the transceiver's internal RC oscillator (which is calibrated against
|
||||
the transceiver crystal), or to calibrate the microcontroller internal
|
||||
RC oscillator using the transceiver's clkout. However, that datasheet is
|
||||
a bit vague on the RC oscillator's accuracy and how to use it exactly
|
||||
(some registers seem to be FSK-mode only), so this needs some
|
||||
experiments.
|
||||
|
||||
Downlink datarate
|
||||
-----------------
|
||||
Note that the datarate used for downlink packets in the RX2 window
|
||||
defaults to SF12BW125 according to the specification, but some networks
|
||||
use different values (iot.semtech.com and The Things Network both use
|
||||
SF9BW). When using personalized activate (ABP), it is your
|
||||
responsibility to set the right settings, e.g. by adding this to your
|
||||
sketch (after calling `LMIC_setSession`). `ttn-abp.ino` already does
|
||||
this.
|
||||
|
||||
LMIC.dn2Dr = DR_SF9;
|
||||
|
||||
When using OTAA, the network communicates the RX2 settings in the
|
||||
join accept message, but the LMIC library does not currently process
|
||||
these settings. Until that is solved (see issue #20), you should
|
||||
manually set the RX2 rate, *after* joining (see the handling of
|
||||
`EV_JOINED` in the `ttn-otaa.ino` for an example.
|
||||
|
||||
License
|
||||
-------
|
||||
Most source files in this repository are made available under the
|
||||
Eclipse Public License v1.0. The examples which use a more liberal
|
||||
license. Some of the AES code is available under the LGPL. Refer to each
|
||||
individual source file for more details.
|
BIN
lib/arduino-lmic-1.5.0-arduino-2-tweaked/doc/LMiC-v1.5.pdf
Normal file
BIN
lib/arduino-lmic-1.5.0-arduino-2-tweaked/doc/LMiC-v1.5.pdf
Normal file
Binary file not shown.
4
lib/arduino-lmic-1.5.0-arduino-2-tweaked/doc/README.txt
Normal file
4
lib/arduino-lmic-1.5.0-arduino-2-tweaked/doc/README.txt
Normal file
@ -0,0 +1,4 @@
|
||||
DISCLAIMER:
|
||||
Please note that the software is provided AS IS and we cannot
|
||||
provide support for optimizations, adaptations, integration,
|
||||
ports to other platforms or device drivers!
|
@ -0,0 +1,28 @@
|
||||
==============================================================================
|
||||
LMIC VERSION 1.4 (17-Mar-2015)
|
||||
-------------------------------
|
||||
|
||||
- changed API: inverted port indicator flag in LMIC.txrxFlags
|
||||
(now TXRX_PORT, previously TXRX_NOPORT)
|
||||
|
||||
- fixed offset OFF_CFLIST constant
|
||||
|
||||
- changed CRC-16 algorithm for beacons to CCITT(XMODEM) polynomial
|
||||
|
||||
- fixed radio driver (low data rate optimization for SF11+SF12 only for BW125)
|
||||
|
||||
- fixed timer rollover handling in job queue
|
||||
|
||||
==============================================================================
|
||||
LMIC VERSION 1.5 (8-May-2015)
|
||||
------------------------------
|
||||
|
||||
- fixed condition in convFreq()
|
||||
|
||||
- fixed freq*100 bug and freq==0 bug for CFList
|
||||
|
||||
- fixed TX scheduling bug
|
||||
|
||||
- better support for GNU compiler toolchain
|
||||
|
||||
==============================================================================
|
162
lib/arduino-lmic-1.5.0-arduino-2-tweaked/examples/raw/raw.ino
Normal file
162
lib/arduino-lmic-1.5.0-arduino-2-tweaked/examples/raw/raw.ino
Normal file
@ -0,0 +1,162 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Matthijs Kooijman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to anyone
|
||||
* obtaining a copy of this document and accompanying files,
|
||||
* to do whatever they want with them without any restriction,
|
||||
* including, but not limited to, copying, modification and redistribution.
|
||||
* NO WARRANTY OF ANY KIND IS PROVIDED.
|
||||
*
|
||||
* This example transmits data on hardcoded channel and receives data
|
||||
* when not transmitting. Running this sketch on two nodes should allow
|
||||
* them to communicate.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <lmic.h>
|
||||
#include <hal/hal.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#if !defined(DISABLE_INVERT_IQ_ON_RX)
|
||||
#error This example requires DISABLE_INVERT_IQ_ON_RX to be set. Update \
|
||||
config.h in the lmic library to set it.
|
||||
#endif
|
||||
|
||||
// How often to send a packet. Note that this sketch bypasses the normal
|
||||
// LMIC duty cycle limiting, so when you change anything in this sketch
|
||||
// (payload length, frequency, spreading factor), be sure to check if
|
||||
// this interval should not also be increased.
|
||||
// See this spreadsheet for an easy airtime and duty cycle calculator:
|
||||
// https://docs.google.com/spreadsheets/d/1voGAtQAjC1qBmaVuP1ApNKs1ekgUjavHuVQIXyYSvNc
|
||||
#define TX_INTERVAL 2000
|
||||
|
||||
// Pin mapping
|
||||
const lmic_pinmap lmic_pins = {
|
||||
.nss = 6,
|
||||
.rxtx = LMIC_UNUSED_PIN,
|
||||
.rst = 5,
|
||||
.dio = {2, 3, 4},
|
||||
};
|
||||
|
||||
|
||||
// These callbacks are only used in over-the-air activation, so they are
|
||||
// left empty here (we cannot leave them out completely unless
|
||||
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
|
||||
void os_getArtEui (u1_t* buf) { }
|
||||
void os_getDevEui (u1_t* buf) { }
|
||||
void os_getDevKey (u1_t* buf) { }
|
||||
|
||||
void onEvent (ev_t ev) {
|
||||
}
|
||||
|
||||
osjob_t txjob;
|
||||
osjob_t timeoutjob;
|
||||
static void tx_func (osjob_t* job);
|
||||
|
||||
// Transmit the given string and call the given function afterwards
|
||||
void tx(const char *str, osjobcb_t func) {
|
||||
os_radio(RADIO_RST); // Stop RX first
|
||||
delay(1); // Wait a bit, without this os_radio below asserts, apparently because the state hasn't changed yet
|
||||
LMIC.dataLen = 0;
|
||||
while (*str)
|
||||
LMIC.frame[LMIC.dataLen++] = *str++;
|
||||
LMIC.osjob.func = func;
|
||||
os_radio(RADIO_TX);
|
||||
Serial.println("TX");
|
||||
}
|
||||
|
||||
// Enable rx mode and call func when a packet is received
|
||||
void rx(osjobcb_t func) {
|
||||
LMIC.osjob.func = func;
|
||||
LMIC.rxtime = os_getTime(); // RX _now_
|
||||
// Enable "continuous" RX (e.g. without a timeout, still stops after
|
||||
// receiving a packet)
|
||||
os_radio(RADIO_RXON);
|
||||
Serial.println("RX");
|
||||
}
|
||||
|
||||
static void rxtimeout_func(osjob_t *job) {
|
||||
digitalWrite(LED_BUILTIN, LOW); // off
|
||||
}
|
||||
|
||||
static void rx_func (osjob_t* job) {
|
||||
// Blink once to confirm reception and then keep the led on
|
||||
digitalWrite(LED_BUILTIN, LOW); // off
|
||||
delay(10);
|
||||
digitalWrite(LED_BUILTIN, HIGH); // on
|
||||
|
||||
// Timeout RX (i.e. update led status) after 3 periods without RX
|
||||
os_setTimedCallback(&timeoutjob, os_getTime() + ms2osticks(3*TX_INTERVAL), rxtimeout_func);
|
||||
|
||||
// Reschedule TX so that it should not collide with the other side's
|
||||
// next TX
|
||||
os_setTimedCallback(&txjob, os_getTime() + ms2osticks(TX_INTERVAL/2), tx_func);
|
||||
|
||||
Serial.print("Got ");
|
||||
Serial.print(LMIC.dataLen);
|
||||
Serial.println(" bytes");
|
||||
Serial.write(LMIC.frame, LMIC.dataLen);
|
||||
Serial.println();
|
||||
|
||||
// Restart RX
|
||||
rx(rx_func);
|
||||
}
|
||||
|
||||
static void txdone_func (osjob_t* job) {
|
||||
rx(rx_func);
|
||||
}
|
||||
|
||||
// log text to USART and toggle LED
|
||||
static void tx_func (osjob_t* job) {
|
||||
// say hello
|
||||
tx("Hello, world!", txdone_func);
|
||||
// reschedule job every TX_INTERVAL (plus a bit of random to prevent
|
||||
// systematic collisions), unless packets are received, then rx_func
|
||||
// will reschedule at half this time.
|
||||
os_setTimedCallback(job, os_getTime() + ms2osticks(TX_INTERVAL + random(500)), tx_func);
|
||||
}
|
||||
|
||||
// application entry point
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting");
|
||||
#ifdef VCC_ENABLE
|
||||
// For Pinoccio Scout boards
|
||||
pinMode(VCC_ENABLE, OUTPUT);
|
||||
digitalWrite(VCC_ENABLE, HIGH);
|
||||
delay(1000);
|
||||
#endif
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
// initialize runtime env
|
||||
os_init();
|
||||
|
||||
// Set up these settings once, and use them for both TX and RX
|
||||
|
||||
#if defined(CFG_eu868)
|
||||
// Use a frequency in the g3 which allows 10% duty cycling.
|
||||
LMIC.freq = 869525000;
|
||||
#elif defined(CFG_us915)
|
||||
LMIC.freq = 902300000;
|
||||
#endif
|
||||
|
||||
// Maximum TX power
|
||||
LMIC.txpow = 27;
|
||||
// Use a medium spread factor. This can be increased up to SF12 for
|
||||
// better range, but then the interval should be (significantly)
|
||||
// lowered to comply with duty cycle limits as well.
|
||||
LMIC.datarate = DR_SF9;
|
||||
// This sets CR 4/5, BW125 (except for DR_SF7B, which uses BW250)
|
||||
LMIC.rps = updr2rps(LMIC.datarate);
|
||||
|
||||
Serial.println("Started");
|
||||
Serial.flush();
|
||||
|
||||
// setup initial job
|
||||
os_setCallback(&txjob, tx_func);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// execute scheduled jobs and events
|
||||
os_runloop_once();
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to anyone
|
||||
* obtaining a copy of this document and accompanying files,
|
||||
* to do whatever they want with them without any restriction,
|
||||
* including, but not limited to, copying, modification and redistribution.
|
||||
* NO WARRANTY OF ANY KIND IS PROVIDED.
|
||||
*
|
||||
* This example sends a valid LoRaWAN packet with payload "Hello,
|
||||
* world!", using frequency and encryption settings matching those of
|
||||
* the The Things Network.
|
||||
*
|
||||
* This uses ABP (Activation-by-personalisation), where a DevAddr and
|
||||
* Session keys are preconfigured (unlike OTAA, where a DevEUI and
|
||||
* application key is configured, while the DevAddr and session keys are
|
||||
* assigned/generated in the over-the-air-activation procedure).
|
||||
*
|
||||
* Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in
|
||||
* g1, 0.1% in g2), but not the TTN fair usage policy (which is probably
|
||||
* violated by this sketch when left running for longer)!
|
||||
*
|
||||
* To use this sketch, first register your application and device with
|
||||
* the things network, to set or generate a DevAddr, NwkSKey and
|
||||
* AppSKey. Each device should have their own unique values for these
|
||||
* fields.
|
||||
*
|
||||
* Do not forget to define the radio type correctly in config.h.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <lmic.h>
|
||||
#include <hal/hal.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// LoRaWAN NwkSKey, network session key
|
||||
// This is the default Semtech key, which is used by the early prototype TTN
|
||||
// network.
|
||||
static const PROGMEM u1_t NWKSKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
|
||||
|
||||
// LoRaWAN AppSKey, application session key
|
||||
// This is the default Semtech key, which is used by the early prototype TTN
|
||||
// network.
|
||||
static const u1_t PROGMEM APPSKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
|
||||
|
||||
// LoRaWAN end-device address (DevAddr)
|
||||
static const u4_t DEVADDR = 0x03FF0001 ; // <-- Change this address for every node!
|
||||
|
||||
// These callbacks are only used in over-the-air activation, so they are
|
||||
// left empty here (we cannot leave them out completely unless
|
||||
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
|
||||
void os_getArtEui (u1_t* buf) { }
|
||||
void os_getDevEui (u1_t* buf) { }
|
||||
void os_getDevKey (u1_t* buf) { }
|
||||
|
||||
static uint8_t mydata[] = "Hello, world!";
|
||||
static osjob_t sendjob;
|
||||
|
||||
// Schedule TX every this many seconds (might become longer due to duty
|
||||
// cycle limitations).
|
||||
const unsigned TX_INTERVAL = 60;
|
||||
|
||||
// Pin mapping
|
||||
const lmic_pinmap lmic_pins = {
|
||||
.nss = 6,
|
||||
.rxtx = LMIC_UNUSED_PIN,
|
||||
.rst = 5,
|
||||
.dio = {2, 3, 4},
|
||||
};
|
||||
|
||||
void onEvent (ev_t ev) {
|
||||
Serial.print(os_getTime());
|
||||
Serial.print(": ");
|
||||
switch(ev) {
|
||||
case EV_SCAN_TIMEOUT:
|
||||
Serial.println(F("EV_SCAN_TIMEOUT"));
|
||||
break;
|
||||
case EV_BEACON_FOUND:
|
||||
Serial.println(F("EV_BEACON_FOUND"));
|
||||
break;
|
||||
case EV_BEACON_MISSED:
|
||||
Serial.println(F("EV_BEACON_MISSED"));
|
||||
break;
|
||||
case EV_BEACON_TRACKED:
|
||||
Serial.println(F("EV_BEACON_TRACKED"));
|
||||
break;
|
||||
case EV_JOINING:
|
||||
Serial.println(F("EV_JOINING"));
|
||||
break;
|
||||
case EV_JOINED:
|
||||
Serial.println(F("EV_JOINED"));
|
||||
break;
|
||||
case EV_RFU1:
|
||||
Serial.println(F("EV_RFU1"));
|
||||
break;
|
||||
case EV_JOIN_FAILED:
|
||||
Serial.println(F("EV_JOIN_FAILED"));
|
||||
break;
|
||||
case EV_REJOIN_FAILED:
|
||||
Serial.println(F("EV_REJOIN_FAILED"));
|
||||
break;
|
||||
case EV_TXCOMPLETE:
|
||||
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
|
||||
if (LMIC.txrxFlags & TXRX_ACK)
|
||||
Serial.println(F("Received ack"));
|
||||
if (LMIC.dataLen) {
|
||||
Serial.println(F("Received "));
|
||||
Serial.println(LMIC.dataLen);
|
||||
Serial.println(F(" bytes of payload"));
|
||||
}
|
||||
// Schedule next transmission
|
||||
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
|
||||
break;
|
||||
case EV_LOST_TSYNC:
|
||||
Serial.println(F("EV_LOST_TSYNC"));
|
||||
break;
|
||||
case EV_RESET:
|
||||
Serial.println(F("EV_RESET"));
|
||||
break;
|
||||
case EV_RXCOMPLETE:
|
||||
// data received in ping slot
|
||||
Serial.println(F("EV_RXCOMPLETE"));
|
||||
break;
|
||||
case EV_LINK_DEAD:
|
||||
Serial.println(F("EV_LINK_DEAD"));
|
||||
break;
|
||||
case EV_LINK_ALIVE:
|
||||
Serial.println(F("EV_LINK_ALIVE"));
|
||||
break;
|
||||
default:
|
||||
Serial.println(F("Unknown event"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void do_send(osjob_t* j){
|
||||
// Check if there is not a current TX/RX job running
|
||||
if (LMIC.opmode & OP_TXRXPEND) {
|
||||
Serial.println(F("OP_TXRXPEND, not sending"));
|
||||
} else {
|
||||
// Prepare upstream data transmission at the next possible time.
|
||||
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
|
||||
Serial.println(F("Packet queued"));
|
||||
}
|
||||
// Next TX is scheduled after TX_COMPLETE event.
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("Starting"));
|
||||
|
||||
#ifdef VCC_ENABLE
|
||||
// For Pinoccio Scout boards
|
||||
pinMode(VCC_ENABLE, OUTPUT);
|
||||
digitalWrite(VCC_ENABLE, HIGH);
|
||||
delay(1000);
|
||||
#endif
|
||||
|
||||
// LMIC init
|
||||
os_init();
|
||||
// Reset the MAC state. Session and pending data transfers will be discarded.
|
||||
LMIC_reset();
|
||||
|
||||
// Set static session parameters. Instead of dynamically establishing a session
|
||||
// by joining the network, precomputed session parameters are be provided.
|
||||
#ifdef PROGMEM
|
||||
// On AVR, these values are stored in flash and only copied to RAM
|
||||
// once. Copy them to a temporary buffer here, LMIC_setSession will
|
||||
// copy them into a buffer of its own again.
|
||||
uint8_t appskey[sizeof(APPSKEY)];
|
||||
uint8_t nwkskey[sizeof(NWKSKEY)];
|
||||
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
|
||||
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
|
||||
LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
|
||||
#else
|
||||
// If not running an AVR with PROGMEM, just use the arrays directly
|
||||
LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);
|
||||
#endif
|
||||
|
||||
#if defined(CFG_eu868)
|
||||
// Set up the channels used by the Things Network, which corresponds
|
||||
// to the defaults of most gateways. Without this, only three base
|
||||
// channels from the LoRaWAN specification are used, which certainly
|
||||
// works, so it is good for debugging, but can overload those
|
||||
// frequencies, so be sure to configure the full frequency range of
|
||||
// your network here (unless your network autoconfigures them).
|
||||
// Setting up channels should happen after LMIC_setSession, as that
|
||||
// configures the minimal channel set.
|
||||
// NA-US channels 0-71 are configured automatically
|
||||
LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
||||
LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band
|
||||
LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
||||
LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
||||
LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
||||
LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
||||
LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
||||
LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
||||
LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band
|
||||
// TTN defines an additional channel at 869.525Mhz using SF9 for class B
|
||||
// devices' ping slots. LMIC does not have an easy way to define set this
|
||||
// frequency and support for class B is spotty and untested, so this
|
||||
// frequency is not configured here.
|
||||
#elif defined(CFG_us915)
|
||||
// NA-US channels 0-71 are configured automatically
|
||||
// but only one group of 8 should (a subband) should be active
|
||||
// TTN recommends the second sub band, 1 in a zero based count.
|
||||
// https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json
|
||||
LMIC_selectSubBand(1);
|
||||
#endif
|
||||
|
||||
// Disable link check validation
|
||||
LMIC_setLinkCheckMode(0);
|
||||
|
||||
// TTN uses SF9 for its RX2 window.
|
||||
LMIC.dn2Dr = DR_SF9;
|
||||
|
||||
// Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
|
||||
LMIC_setDrTxpow(DR_SF7,14);
|
||||
|
||||
// Start job
|
||||
do_send(&sendjob);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
os_runloop_once();
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to anyone
|
||||
* obtaining a copy of this document and accompanying files,
|
||||
* to do whatever they want with them without any restriction,
|
||||
* including, but not limited to, copying, modification and redistribution.
|
||||
* NO WARRANTY OF ANY KIND IS PROVIDED.
|
||||
*
|
||||
* This example sends a valid LoRaWAN packet with payload "Hello,
|
||||
* world!", using frequency and encryption settings matching those of
|
||||
* the The Things Network.
|
||||
*
|
||||
* This uses OTAA (Over-the-air activation), where where a DevEUI and
|
||||
* application key is configured, which are used in an over-the-air
|
||||
* activation procedure where a DevAddr and session keys are
|
||||
* assigned/generated for use with all further communication.
|
||||
*
|
||||
* Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in
|
||||
* g1, 0.1% in g2), but not the TTN fair usage policy (which is probably
|
||||
* violated by this sketch when left running for longer)!
|
||||
|
||||
* To use this sketch, first register your application and device with
|
||||
* the things network, to set or generate an AppEUI, DevEUI and AppKey.
|
||||
* Multiple devices can use the same AppEUI, but each device has its own
|
||||
* DevEUI and AppKey.
|
||||
*
|
||||
* Do not forget to define the radio type correctly in config.h.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <lmic.h>
|
||||
#include <hal/hal.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// This EUI must be in little-endian format, so least-significant-byte
|
||||
// first. When copying an EUI from ttnctl output, this means to reverse
|
||||
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
|
||||
// 0x70.
|
||||
static const u1_t PROGMEM APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}
|
||||
|
||||
// This should also be in little endian format, see above.
|
||||
static const u1_t PROGMEM DEVEUI[8]={ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}
|
||||
|
||||
// This key should be in big endian format (or, since it is not really a
|
||||
// number but a block of memory, endianness does not really apply). In
|
||||
// practice, a key taken from ttnctl can be copied as-is.
|
||||
// The key shown here is the semtech default key.
|
||||
static const u1_t PROGMEM APPKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
|
||||
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}
|
||||
|
||||
static uint8_t mydata[] = "Hello, world!";
|
||||
static osjob_t sendjob;
|
||||
|
||||
// Schedule TX every this many seconds (might become longer due to duty
|
||||
// cycle limitations).
|
||||
const unsigned TX_INTERVAL = 60;
|
||||
|
||||
// Pin mapping
|
||||
const lmic_pinmap lmic_pins = {
|
||||
.nss = 6,
|
||||
.rxtx = LMIC_UNUSED_PIN,
|
||||
.rst = 5,
|
||||
.dio = {2, 3, 4},
|
||||
};
|
||||
|
||||
void onEvent (ev_t ev) {
|
||||
Serial.print(os_getTime());
|
||||
Serial.print(": ");
|
||||
switch(ev) {
|
||||
case EV_SCAN_TIMEOUT:
|
||||
Serial.println(F("EV_SCAN_TIMEOUT"));
|
||||
break;
|
||||
case EV_BEACON_FOUND:
|
||||
Serial.println(F("EV_BEACON_FOUND"));
|
||||
break;
|
||||
case EV_BEACON_MISSED:
|
||||
Serial.println(F("EV_BEACON_MISSED"));
|
||||
break;
|
||||
case EV_BEACON_TRACKED:
|
||||
Serial.println(F("EV_BEACON_TRACKED"));
|
||||
break;
|
||||
case EV_JOINING:
|
||||
Serial.println(F("EV_JOINING"));
|
||||
break;
|
||||
case EV_JOINED:
|
||||
Serial.println(F("EV_JOINED"));
|
||||
|
||||
// Disable link check validation (automatically enabled
|
||||
// during join, but not supported by TTN at this time).
|
||||
LMIC_setLinkCheckMode(0);
|
||||
break;
|
||||
case EV_RFU1:
|
||||
Serial.println(F("EV_RFU1"));
|
||||
break;
|
||||
case EV_JOIN_FAILED:
|
||||
Serial.println(F("EV_JOIN_FAILED"));
|
||||
break;
|
||||
case EV_REJOIN_FAILED:
|
||||
Serial.println(F("EV_REJOIN_FAILED"));
|
||||
break;
|
||||
break;
|
||||
case EV_TXCOMPLETE:
|
||||
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
|
||||
if (LMIC.txrxFlags & TXRX_ACK)
|
||||
Serial.println(F("Received ack"));
|
||||
if (LMIC.dataLen) {
|
||||
Serial.println(F("Received "));
|
||||
Serial.println(LMIC.dataLen);
|
||||
Serial.println(F(" bytes of payload"));
|
||||
}
|
||||
// Schedule next transmission
|
||||
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
|
||||
break;
|
||||
case EV_LOST_TSYNC:
|
||||
Serial.println(F("EV_LOST_TSYNC"));
|
||||
break;
|
||||
case EV_RESET:
|
||||
Serial.println(F("EV_RESET"));
|
||||
break;
|
||||
case EV_RXCOMPLETE:
|
||||
// data received in ping slot
|
||||
Serial.println(F("EV_RXCOMPLETE"));
|
||||
break;
|
||||
case EV_LINK_DEAD:
|
||||
Serial.println(F("EV_LINK_DEAD"));
|
||||
break;
|
||||
case EV_LINK_ALIVE:
|
||||
Serial.println(F("EV_LINK_ALIVE"));
|
||||
break;
|
||||
default:
|
||||
Serial.println(F("Unknown event"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void do_send(osjob_t* j){
|
||||
// Check if there is not a current TX/RX job running
|
||||
if (LMIC.opmode & OP_TXRXPEND) {
|
||||
Serial.println(F("OP_TXRXPEND, not sending"));
|
||||
} else {
|
||||
// Prepare upstream data transmission at the next possible time.
|
||||
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
|
||||
Serial.println(F("Packet queued"));
|
||||
}
|
||||
// Next TX is scheduled after TX_COMPLETE event.
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("Starting"));
|
||||
|
||||
#ifdef VCC_ENABLE
|
||||
// For Pinoccio Scout boards
|
||||
pinMode(VCC_ENABLE, OUTPUT);
|
||||
digitalWrite(VCC_ENABLE, HIGH);
|
||||
delay(1000);
|
||||
#endif
|
||||
|
||||
// LMIC init
|
||||
os_init();
|
||||
// Reset the MAC state. Session and pending data transfers will be discarded.
|
||||
LMIC_reset();
|
||||
|
||||
// Start job (sending automatically starts OTAA too)
|
||||
do_send(&sendjob);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
os_runloop_once();
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
name=IBM LMIC framework
|
||||
version=1.5.0+arduino-2
|
||||
author=IBM
|
||||
maintainer=Matthijs Kooijman <matthijs@stdin.nl>
|
||||
sentence=Arduino port of the LMIC (LoraWAN-in-C, formerly LoraMAC-in-C) framework provided by IBM.
|
||||
paragraph=Supports SX1272/SX1276 and HopeRF RFM92/RFM95 tranceivers
|
||||
category=Communication
|
||||
url=http://www.research.ibm.com/labs/zurich/ics/lrsc/lmic.html
|
||||
architectures=*
|
@ -0,0 +1,342 @@
|
||||
/******************************************************************************************
|
||||
#if defined(USE_IDEETRON_AES)
|
||||
* Copyright 2015, 2016 Ideetron B.V.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************************/
|
||||
/******************************************************************************************
|
||||
*
|
||||
* File: AES-128_V10.cpp
|
||||
* Author: Gerben den Hartog
|
||||
* Compagny: Ideetron B.V.
|
||||
* Website: http://www.ideetron.nl/LoRa
|
||||
* E-mail: info@ideetron.nl
|
||||
******************************************************************************************/
|
||||
/****************************************************************************************
|
||||
*
|
||||
* Created on: 20-10-2015
|
||||
* Supported Hardware: ID150119-02 Nexus board with RFM95
|
||||
*
|
||||
* Firmware Version 1.0
|
||||
* First version
|
||||
****************************************************************************************/
|
||||
|
||||
// This file was taken from
|
||||
// https://github.com/Ideetron/RFM95W_Nexus/tree/master/LoRaWAN_V31 for
|
||||
// use with LMIC. It was only cosmetically modified:
|
||||
// - AES_Encrypt was renamed to lmic_aes_encrypt.
|
||||
// - All other functions and variables were made static
|
||||
// - Tabs were converted to 2 spaces
|
||||
// - An #include and #if guard was added
|
||||
// - S_Table is now stored in PROGMEM
|
||||
|
||||
#include "../../lmic/oslmic.h"
|
||||
|
||||
#if defined(USE_IDEETRON_AES)
|
||||
|
||||
/*
|
||||
********************************************************************************************
|
||||
* Global Variables
|
||||
********************************************************************************************
|
||||
*/
|
||||
|
||||
static unsigned char State[4][4];
|
||||
|
||||
static CONST_TABLE(unsigned char, S_Table)[16][16] = {
|
||||
{0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76},
|
||||
{0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0},
|
||||
{0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15},
|
||||
{0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75},
|
||||
{0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84},
|
||||
{0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF},
|
||||
{0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8},
|
||||
{0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2},
|
||||
{0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73},
|
||||
{0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB},
|
||||
{0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79},
|
||||
{0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08},
|
||||
{0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A},
|
||||
{0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E},
|
||||
{0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF},
|
||||
{0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16}
|
||||
};
|
||||
|
||||
extern "C" void lmic_aes_encrypt(unsigned char *Data, unsigned char *Key);
|
||||
static void AES_Add_Round_Key(unsigned char *Round_Key);
|
||||
static unsigned char AES_Sub_Byte(unsigned char Byte);
|
||||
static void AES_Shift_Rows();
|
||||
static void AES_Mix_Collums();
|
||||
static void AES_Calculate_Round_Key(unsigned char Round, unsigned char *Round_Key);
|
||||
static void Send_State();
|
||||
|
||||
/*
|
||||
*****************************************************************************************
|
||||
* Description : Function for encrypting data using AES-128
|
||||
*
|
||||
* Arguments : *Data Data to encrypt is a 16 byte long arry
|
||||
* *Key Key to encrypt data with is a 16 byte long arry
|
||||
*****************************************************************************************
|
||||
*/
|
||||
void lmic_aes_encrypt(unsigned char *Data, unsigned char *Key)
|
||||
{
|
||||
unsigned char i;
|
||||
unsigned char Row,Collum;
|
||||
unsigned char Round = 0x00;
|
||||
unsigned char Round_Key[16];
|
||||
|
||||
//Copy input to State arry
|
||||
for(Collum = 0; Collum < 4; Collum++)
|
||||
{
|
||||
for(Row = 0; Row < 4; Row++)
|
||||
{
|
||||
State[Row][Collum] = Data[Row + (4*Collum)];
|
||||
}
|
||||
}
|
||||
|
||||
//Copy key to round key
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
Round_Key[i] = Key[i];
|
||||
}
|
||||
|
||||
//Add round key
|
||||
AES_Add_Round_Key(Round_Key);
|
||||
|
||||
//Preform 9 full rounds
|
||||
for(Round = 1; Round < 10; Round++)
|
||||
{
|
||||
//Preform Byte substitution with S table
|
||||
for(Collum = 0; Collum < 4; Collum++)
|
||||
{
|
||||
for(Row = 0; Row < 4; Row++)
|
||||
{
|
||||
State[Row][Collum] = AES_Sub_Byte(State[Row][Collum]);
|
||||
}
|
||||
}
|
||||
|
||||
//Preform Row Shift
|
||||
AES_Shift_Rows();
|
||||
|
||||
//Mix Collums
|
||||
AES_Mix_Collums();
|
||||
|
||||
//Calculate new round key
|
||||
AES_Calculate_Round_Key(Round,Round_Key);
|
||||
|
||||
//Add round key
|
||||
AES_Add_Round_Key(Round_Key);
|
||||
}
|
||||
|
||||
//Last round whitout mix collums
|
||||
//Preform Byte substitution with S table
|
||||
for(Collum = 0; Collum < 4; Collum++)
|
||||
{
|
||||
for(Row = 0; Row < 4; Row++)
|
||||
{
|
||||
State[Row][Collum] = AES_Sub_Byte(State[Row][Collum]);
|
||||
}
|
||||
}
|
||||
|
||||
//Shift rows
|
||||
AES_Shift_Rows();
|
||||
|
||||
//Calculate new round key
|
||||
AES_Calculate_Round_Key(Round,Round_Key);
|
||||
|
||||
//Add round Key
|
||||
AES_Add_Round_Key(Round_Key);
|
||||
|
||||
//Copy the State into the data array
|
||||
for(Collum = 0; Collum < 4; Collum++)
|
||||
{
|
||||
for(Row = 0; Row < 4; Row++)
|
||||
{
|
||||
Data[Row + (4*Collum)] = State[Row][Collum];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************************************************************
|
||||
* Description : Function that add's the round key for the current round
|
||||
*
|
||||
* Arguments : *Round_Key 16 byte long array holding the Round Key
|
||||
*****************************************************************************************
|
||||
*/
|
||||
static void AES_Add_Round_Key(unsigned char *Round_Key)
|
||||
{
|
||||
unsigned char Row,Collum;
|
||||
|
||||
for(Collum = 0; Collum < 4; Collum++)
|
||||
{
|
||||
for(Row = 0; Row < 4; Row++)
|
||||
{
|
||||
State[Row][Collum] = State[Row][Collum] ^ Round_Key[Row + (4*Collum)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************************************************************
|
||||
* Description : Function that substitutes a byte with a byte from the S_Table
|
||||
*
|
||||
* Arguments : Byte The byte that will be substituted
|
||||
*
|
||||
* Return : The return is the found byte in the S_Table
|
||||
*****************************************************************************************
|
||||
*/
|
||||
static unsigned char AES_Sub_Byte(unsigned char Byte)
|
||||
{
|
||||
unsigned char S_Row,S_Collum;
|
||||
unsigned char S_Byte;
|
||||
|
||||
//Split byte up in Row and Collum
|
||||
S_Row = ((Byte >> 4) & 0x0F);
|
||||
S_Collum = (Byte & 0x0F);
|
||||
|
||||
//Find the correct byte in the S_Table
|
||||
S_Byte = TABLE_GET_U1_TWODIM(S_Table, S_Row, S_Collum);
|
||||
|
||||
return S_Byte;
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************************************************************
|
||||
* Description : Function that preforms the shift row operation described in the AES standard
|
||||
*****************************************************************************************
|
||||
*/
|
||||
static void AES_Shift_Rows()
|
||||
{
|
||||
unsigned char Buffer;
|
||||
|
||||
//Row 0 doesn't change
|
||||
|
||||
//Shift Row 1 one left
|
||||
//Store firt byte in buffer
|
||||
Buffer = State[1][0];
|
||||
//Shift all bytes
|
||||
State[1][0] = State[1][1];
|
||||
State[1][1] = State[1][2];
|
||||
State[1][2] = State[1][3];
|
||||
State[1][3] = Buffer;
|
||||
|
||||
//Shift row 2 two left
|
||||
Buffer = State[2][0];
|
||||
State[2][0] = State[2][2];
|
||||
State[2][2] = Buffer;
|
||||
Buffer = State[2][1];
|
||||
State[2][1] = State[2][3];
|
||||
State[2][3] = Buffer;
|
||||
|
||||
//Shift row 3 three left
|
||||
Buffer = State[3][3];
|
||||
State[3][3] = State[3][2];
|
||||
State[3][2] = State[3][1];
|
||||
State[3][1] = State[3][0];
|
||||
State[3][0] = Buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************************************************************
|
||||
* Description : Function that preforms the Mix Collums operation described in the AES standard
|
||||
*****************************************************************************************
|
||||
*/
|
||||
static void AES_Mix_Collums()
|
||||
{
|
||||
unsigned char Row,Collum;
|
||||
unsigned char a[4], b[4];
|
||||
for(Collum = 0; Collum < 4; Collum++)
|
||||
{
|
||||
for(Row = 0; Row < 4; Row++)
|
||||
{
|
||||
a[Row] = State[Row][Collum];
|
||||
b[Row] = (State[Row][Collum] << 1);
|
||||
|
||||
if((State[Row][Collum] & 0x80) == 0x80)
|
||||
{
|
||||
b[Row] = b[Row] ^ 0x1B;
|
||||
}
|
||||
}
|
||||
State[0][Collum] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3];
|
||||
State[1][Collum] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3];
|
||||
State[2][Collum] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3];
|
||||
State[3][Collum] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************************************************************
|
||||
* Description : Function that calculaties the round key for the current round
|
||||
*
|
||||
* Arguments : Round Number of current Round
|
||||
* *Round_Key 16 byte long array holding the Round Key
|
||||
*****************************************************************************************
|
||||
*/
|
||||
static void AES_Calculate_Round_Key(unsigned char Round, unsigned char *Round_Key)
|
||||
{
|
||||
unsigned char i,j;
|
||||
unsigned char b;
|
||||
unsigned char Temp[4];
|
||||
unsigned char Buffer;
|
||||
unsigned char Rcon;
|
||||
|
||||
//Calculate first Temp
|
||||
//Copy laste byte from previous key
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
Temp[i] = Round_Key[i+12];
|
||||
}
|
||||
|
||||
//Rotate Temp
|
||||
Buffer = Temp[0];
|
||||
Temp[0] = Temp[1];
|
||||
Temp[1] = Temp[2];
|
||||
Temp[2] = Temp[3];
|
||||
Temp[3] = Buffer;
|
||||
|
||||
//Substitute Temp
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
Temp[i] = AES_Sub_Byte(Temp[i]);
|
||||
}
|
||||
|
||||
//Calculate Rcon
|
||||
Rcon = 0x01;
|
||||
while(Round != 1)
|
||||
{
|
||||
b = Rcon & 0x80;
|
||||
Rcon = Rcon << 1;
|
||||
if(b == 0x80)
|
||||
{
|
||||
Rcon = Rcon ^ 0x1b;
|
||||
}
|
||||
Round--;
|
||||
}
|
||||
|
||||
//XOR Rcon
|
||||
Temp[0] = Temp[0] ^ Rcon;
|
||||
|
||||
//Calculate new key
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
for(j = 0; j < 4; j++)
|
||||
{
|
||||
Round_Key[j + (4*i)] = Round_Key[j + (4*i)] ^ Temp[j];
|
||||
Temp[j] = Round_Key[j + (4*i)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(USE_IDEETRON_AES)
|
370
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/aes/lmic.c
Normal file
370
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/aes/lmic.c
Normal file
@ -0,0 +1,370 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014-2015 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Zurich Research Lab - initial API, implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "../lmic/oslmic.h"
|
||||
|
||||
#if defined(USE_ORIGINAL_AES)
|
||||
|
||||
#define AES_MICSUB 0x30 // internal use only
|
||||
|
||||
static CONST_TABLE(u4_t, AES_RCON)[10] = {
|
||||
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
|
||||
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000
|
||||
};
|
||||
|
||||
static CONST_TABLE(u1_t, AES_S)[256] = {
|
||||
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
||||
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
||||
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
||||
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
||||
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
||||
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
||||
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
||||
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
||||
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
||||
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
||||
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
||||
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
||||
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
||||
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
||||
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
|
||||
};
|
||||
|
||||
static CONST_TABLE(u4_t, AES_E1)[256] = {
|
||||
0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554,
|
||||
0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A,
|
||||
0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B,
|
||||
0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B,
|
||||
0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F,
|
||||
0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F,
|
||||
0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5,
|
||||
0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F,
|
||||
0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB,
|
||||
0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497,
|
||||
0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED,
|
||||
0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A,
|
||||
0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594,
|
||||
0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3,
|
||||
0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504,
|
||||
0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D,
|
||||
0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739,
|
||||
0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395,
|
||||
0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883,
|
||||
0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76,
|
||||
0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4,
|
||||
0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B,
|
||||
0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0,
|
||||
0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818,
|
||||
0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651,
|
||||
0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85,
|
||||
0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12,
|
||||
0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9,
|
||||
0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7,
|
||||
0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A,
|
||||
0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8,
|
||||
0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A,
|
||||
};
|
||||
|
||||
static CONST_TABLE(u4_t, AES_E2)[256] = {
|
||||
0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5,
|
||||
0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676,
|
||||
0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0,
|
||||
0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0,
|
||||
0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC,
|
||||
0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515,
|
||||
0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A,
|
||||
0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575,
|
||||
0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0,
|
||||
0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484,
|
||||
0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B,
|
||||
0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF,
|
||||
0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585,
|
||||
0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8,
|
||||
0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5,
|
||||
0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2,
|
||||
0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717,
|
||||
0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373,
|
||||
0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888,
|
||||
0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB,
|
||||
0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C,
|
||||
0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979,
|
||||
0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9,
|
||||
0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808,
|
||||
0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6,
|
||||
0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A,
|
||||
0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E,
|
||||
0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E,
|
||||
0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494,
|
||||
0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF,
|
||||
0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868,
|
||||
0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616,
|
||||
};
|
||||
|
||||
static CONST_TABLE(u4_t, AES_E3)[256] = {
|
||||
0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5,
|
||||
0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76,
|
||||
0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0,
|
||||
0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0,
|
||||
0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC,
|
||||
0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15,
|
||||
0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A,
|
||||
0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75,
|
||||
0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0,
|
||||
0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384,
|
||||
0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B,
|
||||
0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF,
|
||||
0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185,
|
||||
0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8,
|
||||
0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5,
|
||||
0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2,
|
||||
0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17,
|
||||
0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673,
|
||||
0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88,
|
||||
0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB,
|
||||
0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C,
|
||||
0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279,
|
||||
0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9,
|
||||
0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008,
|
||||
0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6,
|
||||
0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A,
|
||||
0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E,
|
||||
0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E,
|
||||
0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394,
|
||||
0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF,
|
||||
0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068,
|
||||
0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16,
|
||||
};
|
||||
|
||||
static CONST_TABLE(u4_t, AES_E4)[256] = {
|
||||
0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
|
||||
0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
|
||||
0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
|
||||
0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
|
||||
0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
|
||||
0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
|
||||
0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
|
||||
0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
|
||||
0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
|
||||
0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
|
||||
0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
|
||||
0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
|
||||
0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
|
||||
0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
|
||||
0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
|
||||
0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
|
||||
0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
|
||||
0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
|
||||
0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
|
||||
0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
|
||||
0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
|
||||
0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
|
||||
0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
|
||||
0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
|
||||
0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
|
||||
0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
|
||||
0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
|
||||
0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
|
||||
0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
|
||||
0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
|
||||
0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
|
||||
0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C,
|
||||
};
|
||||
|
||||
#define msbf4_read(p) ((p)[0]<<24 | (p)[1]<<16 | (p)[2]<<8 | (p)[3])
|
||||
#define msbf4_write(p,v) (p)[0]=(v)>>24,(p)[1]=(v)>>16,(p)[2]=(v)>>8,(p)[3]=(v)
|
||||
#define swapmsbf(x) ( (x&0xFF)<<24 | (x&0xFF00)<<8 | (x&0xFF0000)>>8 | (x>>24) )
|
||||
|
||||
#define u1(v) ((u1_t)(v))
|
||||
|
||||
#define AES_key4(r1,r2,r3,r0,i) r1 = ki[i+1]; \
|
||||
r2 = ki[i+2]; \
|
||||
r3 = ki[i+3]; \
|
||||
r0 = ki[i]
|
||||
|
||||
#define AES_expr4(r1,r2,r3,r0,i) r1 ^= TABLE_GET_U4(AES_E4, u1(i)); \
|
||||
r2 ^= TABLE_GET_U4(AES_E3, u1(i>>8)); \
|
||||
r3 ^= TABLE_GET_U4(AES_E2, u1(i>>16)); \
|
||||
r0 ^= TABLE_GET_U4(AES_E1, (i>>24))
|
||||
|
||||
#define AES_expr(a,r0,r1,r2,r3,i) a = ki[i]; \
|
||||
a ^= ((u4_t)TABLE_GET_U1(AES_S, r0>>24 )<<24); \
|
||||
a ^= ((u4_t)TABLE_GET_U1(AES_S, u1(r1>>16))<<16); \
|
||||
a ^= ((u4_t)TABLE_GET_U1(AES_S, u1(r2>> 8))<< 8); \
|
||||
a ^= (u4_t)TABLE_GET_U1(AES_S, u1(r3) )
|
||||
|
||||
// global area for passing parameters (aux, key) and for storing round keys
|
||||
u4_t AESAUX[16/sizeof(u4_t)];
|
||||
u4_t AESKEY[11*16/sizeof(u4_t)];
|
||||
|
||||
// generate 1+10 roundkeys for encryption with 128-bit key
|
||||
// read 128-bit key from AESKEY in MSBF, generate roundkey words in place
|
||||
static void aesroundkeys () {
|
||||
int i;
|
||||
u4_t b;
|
||||
|
||||
for( i=0; i<4; i++) {
|
||||
AESKEY[i] = swapmsbf(AESKEY[i]);
|
||||
}
|
||||
|
||||
b = AESKEY[3];
|
||||
for( ; i<44; i++ ) {
|
||||
if( i%4==0 ) {
|
||||
// b = SubWord(RotWord(b)) xor Rcon[i/4]
|
||||
b = ((u4_t)TABLE_GET_U1(AES_S, u1(b >> 16)) << 24) ^
|
||||
((u4_t)TABLE_GET_U1(AES_S, u1(b >> 8)) << 16) ^
|
||||
((u4_t)TABLE_GET_U1(AES_S, u1(b) ) << 8) ^
|
||||
((u4_t)TABLE_GET_U1(AES_S, b >> 24 ) ) ^
|
||||
TABLE_GET_U4(AES_RCON, (i-4)/4);
|
||||
}
|
||||
AESKEY[i] = b ^= AESKEY[i-4];
|
||||
}
|
||||
}
|
||||
|
||||
u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) {
|
||||
|
||||
aesroundkeys();
|
||||
|
||||
if( mode & AES_MICNOAUX ) {
|
||||
AESAUX[0] = AESAUX[1] = AESAUX[2] = AESAUX[3] = 0;
|
||||
} else {
|
||||
AESAUX[0] = swapmsbf(AESAUX[0]);
|
||||
AESAUX[1] = swapmsbf(AESAUX[1]);
|
||||
AESAUX[2] = swapmsbf(AESAUX[2]);
|
||||
AESAUX[3] = swapmsbf(AESAUX[3]);
|
||||
}
|
||||
|
||||
while( (signed char)len > 0 ) {
|
||||
u4_t a0, a1, a2, a3;
|
||||
u4_t t0, t1, t2, t3;
|
||||
u4_t *ki, *ke;
|
||||
|
||||
// load input block
|
||||
if( (mode & AES_CTR) || ((mode & AES_MIC) && (mode & AES_MICNOAUX)==0) ) { // load CTR block or first MIC block
|
||||
a0 = AESAUX[0];
|
||||
a1 = AESAUX[1];
|
||||
a2 = AESAUX[2];
|
||||
a3 = AESAUX[3];
|
||||
}
|
||||
else if( (mode & AES_MIC) && len <= 16 ) { // last MIC block
|
||||
a0 = a1 = a2 = a3 = 0; // load null block
|
||||
mode |= ((len == 16) ? 1 : 2) << 4; // set MICSUB: CMAC subkey K1 or K2
|
||||
} else
|
||||
LOADDATA: { // load data block (partially)
|
||||
for(t0=0; t0<16; t0++) {
|
||||
t1 = (t1<<8) | ((t0<len) ? buf[t0] : (t0==len) ? 0x80 : 0x00);
|
||||
if((t0&3)==3) {
|
||||
a0 = a1;
|
||||
a1 = a2;
|
||||
a2 = a3;
|
||||
a3 = t1;
|
||||
}
|
||||
}
|
||||
if( mode & AES_MIC ) {
|
||||
a0 ^= AESAUX[0];
|
||||
a1 ^= AESAUX[1];
|
||||
a2 ^= AESAUX[2];
|
||||
a3 ^= AESAUX[3];
|
||||
}
|
||||
}
|
||||
|
||||
// perform AES encryption on block in a0-a3
|
||||
ki = AESKEY;
|
||||
ke = ki + 8*4;
|
||||
a0 ^= ki[0];
|
||||
a1 ^= ki[1];
|
||||
a2 ^= ki[2];
|
||||
a3 ^= ki[3];
|
||||
do {
|
||||
AES_key4 (t1,t2,t3,t0,4);
|
||||
AES_expr4(t1,t2,t3,t0,a0);
|
||||
AES_expr4(t2,t3,t0,t1,a1);
|
||||
AES_expr4(t3,t0,t1,t2,a2);
|
||||
AES_expr4(t0,t1,t2,t3,a3);
|
||||
|
||||
AES_key4 (a1,a2,a3,a0,8);
|
||||
AES_expr4(a1,a2,a3,a0,t0);
|
||||
AES_expr4(a2,a3,a0,a1,t1);
|
||||
AES_expr4(a3,a0,a1,a2,t2);
|
||||
AES_expr4(a0,a1,a2,a3,t3);
|
||||
} while( (ki+=8) < ke );
|
||||
|
||||
AES_key4 (t1,t2,t3,t0,4);
|
||||
AES_expr4(t1,t2,t3,t0,a0);
|
||||
AES_expr4(t2,t3,t0,t1,a1);
|
||||
AES_expr4(t3,t0,t1,t2,a2);
|
||||
AES_expr4(t0,t1,t2,t3,a3);
|
||||
|
||||
AES_expr(a0,t0,t1,t2,t3,8);
|
||||
AES_expr(a1,t1,t2,t3,t0,9);
|
||||
AES_expr(a2,t2,t3,t0,t1,10);
|
||||
AES_expr(a3,t3,t0,t1,t2,11);
|
||||
// result of AES encryption in a0-a3
|
||||
|
||||
if( mode & AES_MIC ) {
|
||||
if( (t1 = (mode & AES_MICSUB) >> 4) != 0 ) { // last block
|
||||
do {
|
||||
// compute CMAC subkey K1 and K2
|
||||
t0 = a0 >> 31; // save MSB
|
||||
a0 = (a0 << 1) | (a1 >> 31);
|
||||
a1 = (a1 << 1) | (a2 >> 31);
|
||||
a2 = (a2 << 1) | (a3 >> 31);
|
||||
a3 = (a3 << 1);
|
||||
if( t0 ) a3 ^= 0x87;
|
||||
} while( --t1 );
|
||||
|
||||
AESAUX[0] ^= a0;
|
||||
AESAUX[1] ^= a1;
|
||||
AESAUX[2] ^= a2;
|
||||
AESAUX[3] ^= a3;
|
||||
mode &= ~AES_MICSUB;
|
||||
goto LOADDATA;
|
||||
} else {
|
||||
// save cipher block as new iv
|
||||
AESAUX[0] = a0;
|
||||
AESAUX[1] = a1;
|
||||
AESAUX[2] = a2;
|
||||
AESAUX[3] = a3;
|
||||
}
|
||||
} else { // CIPHER
|
||||
if( mode & AES_CTR ) { // xor block (partially)
|
||||
t0 = (len > 16) ? 16: len;
|
||||
for(t1=0; t1<t0; t1++) {
|
||||
buf[t1] ^= (a0>>24);
|
||||
a0 <<= 8;
|
||||
if((t1&3)==3) {
|
||||
a0 = a1;
|
||||
a1 = a2;
|
||||
a2 = a3;
|
||||
}
|
||||
}
|
||||
// update counter
|
||||
AESAUX[3]++;
|
||||
} else { // ECB
|
||||
// store block
|
||||
msbf4_write(buf+0, a0);
|
||||
msbf4_write(buf+4, a1);
|
||||
msbf4_write(buf+8, a2);
|
||||
msbf4_write(buf+12, a3);
|
||||
}
|
||||
}
|
||||
|
||||
// update block state
|
||||
if( (mode & AES_MIC)==0 || (mode & AES_MICNOAUX) ) {
|
||||
buf += 16;
|
||||
len -= 16;
|
||||
}
|
||||
mode |= AES_MICNOAUX;
|
||||
}
|
||||
return AESAUX[0];
|
||||
}
|
||||
|
||||
#endif
|
145
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/aes/other.c
Normal file
145
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/aes/other.c
Normal file
@ -0,0 +1,145 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Matthijs Kooijman
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to anyone
|
||||
* obtaining a copy of this document and accompanying files,
|
||||
* to do whatever they want with them without any restriction,
|
||||
* including, but not limited to, copying, modification and
|
||||
* redistribution.
|
||||
*
|
||||
* NO WARRANTY OF ANY KIND IS PROVIDED.
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
* The original LMIC AES implementation integrates raw AES encryption
|
||||
* with CMAC and AES-CTR in a single piece of code. Most other AES
|
||||
* implementations (only) offer raw single block AES encryption, so this
|
||||
* file contains an implementation of CMAC and AES-CTR, and offers the
|
||||
* same API through the os_aes() function as the original AES
|
||||
* implementation. This file assumes that there is an encryption
|
||||
* function available with this signature:
|
||||
*
|
||||
* extern "C" void lmic_aes_encrypt(u1_t *data, u1_t *key);
|
||||
*
|
||||
* That takes a single 16-byte buffer and encrypts it wit the given
|
||||
* 16-byte key.
|
||||
*/
|
||||
|
||||
#include "../lmic/oslmic.h"
|
||||
|
||||
#if !defined(USE_ORIGINAL_AES)
|
||||
|
||||
// This should be defined elsewhere
|
||||
void lmic_aes_encrypt(u1_t *data, u1_t *key);
|
||||
|
||||
// global area for passing parameters (aux, key)
|
||||
u4_t AESAUX[16/sizeof(u4_t)];
|
||||
u4_t AESKEY[16/sizeof(u4_t)];
|
||||
|
||||
// Shift the given buffer left one bit
|
||||
static void shift_left(xref2u1_t buf, u1_t len) {
|
||||
while (len--) {
|
||||
u1_t next = len ? buf[1] : 0;
|
||||
|
||||
u1_t val = (*buf << 1);
|
||||
if (next & 0x80)
|
||||
val |= 1;
|
||||
*buf++ = val;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply RFC4493 CMAC, using AESKEY as the key. If prepend_aux is true,
|
||||
// AESAUX is prepended to the message. AESAUX is used as working memory
|
||||
// in any case. The CMAC result is returned in AESAUX as well.
|
||||
static void os_aes_cmac(xref2u1_t buf, u2_t len, u1_t prepend_aux) {
|
||||
if (prepend_aux)
|
||||
lmic_aes_encrypt(AESaux, AESkey);
|
||||
else
|
||||
memset (AESaux, 0, 16);
|
||||
|
||||
while (len > 0) {
|
||||
u1_t need_padding = 0;
|
||||
for (u1_t i = 0; i < 16; ++i, ++buf, --len) {
|
||||
if (len == 0) {
|
||||
// The message is padded with 0x80 and then zeroes.
|
||||
// Since zeroes are no-op for xor, we can just skip them
|
||||
// and leave AESAUX unchanged for them.
|
||||
AESaux[i] ^= 0x80;
|
||||
need_padding = 1;
|
||||
break;
|
||||
}
|
||||
AESaux[i] ^= *buf;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
// Final block, xor with K1 or K2. K1 and K2 are calculated
|
||||
// by encrypting the all-zeroes block and then applying some
|
||||
// shifts and xor on that.
|
||||
u1_t final_key[16];
|
||||
memset(final_key, 0, sizeof(final_key));
|
||||
lmic_aes_encrypt(final_key, AESkey);
|
||||
|
||||
// Calculate K1
|
||||
u1_t msb = final_key[0] & 0x80;
|
||||
shift_left(final_key, sizeof(final_key));
|
||||
if (msb)
|
||||
final_key[sizeof(final_key)-1] ^= 0x87;
|
||||
|
||||
// If the final block was not complete, calculate K2 from K1
|
||||
if (need_padding) {
|
||||
msb = final_key[0] & 0x80;
|
||||
shift_left(final_key, sizeof(final_key));
|
||||
if (msb)
|
||||
final_key[sizeof(final_key)-1] ^= 0x87;
|
||||
}
|
||||
|
||||
// Xor with K1 or K2
|
||||
for (u1_t i = 0; i < sizeof(final_key); ++i)
|
||||
AESaux[i] ^= final_key[i];
|
||||
}
|
||||
|
||||
lmic_aes_encrypt(AESaux, AESkey);
|
||||
}
|
||||
}
|
||||
|
||||
// Run AES-CTR using the key in AESKEY and using AESAUX as the
|
||||
// counter block. The last byte of the counter block will be incremented
|
||||
// for every block. The given buffer will be encrypted in place.
|
||||
static void os_aes_ctr (xref2u1_t buf, u2_t len) {
|
||||
u1_t ctr[16];
|
||||
while (len) {
|
||||
// Encrypt the counter block with the selected key
|
||||
memcpy(ctr, AESaux, sizeof(ctr));
|
||||
lmic_aes_encrypt(ctr, AESkey);
|
||||
|
||||
// Xor the payload with the resulting ciphertext
|
||||
for (u1_t i = 0; i < 16 && len > 0; i++, len--, buf++)
|
||||
*buf ^= ctr[i];
|
||||
|
||||
// Increment the block index byte
|
||||
AESaux[15]++;
|
||||
}
|
||||
}
|
||||
|
||||
u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) {
|
||||
switch (mode & ~AES_MICNOAUX) {
|
||||
case AES_MIC:
|
||||
os_aes_cmac(buf, len, /* prepend_aux */ !(mode & AES_MICNOAUX));
|
||||
return os_rmsbf4(AESaux);
|
||||
|
||||
case AES_ENC:
|
||||
// TODO: Check / handle when len is not a multiple of 16
|
||||
for (u1_t i = 0; i < len; i += 16)
|
||||
lmic_aes_encrypt(buf+i, AESkey);
|
||||
break;
|
||||
|
||||
case AES_CTR:
|
||||
os_aes_ctr(buf, len);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // !defined(USE_ORIGINAL_AES)
|
269
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/hal/hal.cpp
Normal file
269
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/hal/hal.cpp
Normal file
@ -0,0 +1,269 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Matthijs Kooijman
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* This the HAL to run LMIC on top of the Arduino environment.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "../lmic.h"
|
||||
#include "hal.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// I/O
|
||||
|
||||
static void hal_io_init () {
|
||||
// NSS and DIO0 are required, DIO1 is required for LoRa, DIO2 for FSK
|
||||
ASSERT(lmic_pins.nss != LMIC_UNUSED_PIN);
|
||||
ASSERT(lmic_pins.dio[0] != LMIC_UNUSED_PIN);
|
||||
ASSERT(lmic_pins.dio[1] != LMIC_UNUSED_PIN || lmic_pins.dio[2] != LMIC_UNUSED_PIN);
|
||||
|
||||
#ifdef LMIC_SPI_PINS_IN_MAPPING
|
||||
ASSERT(lmic_pins.mosi != LMIC_UNUSED_PIN
|
||||
|| lmic_pins.miso != LMIC_UNUSED_PIN
|
||||
|| lmic_pins.sck != LMIC_UNUSED_PIN);
|
||||
#endif
|
||||
|
||||
pinMode(lmic_pins.nss, OUTPUT);
|
||||
if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
|
||||
pinMode(lmic_pins.rxtx, OUTPUT);
|
||||
if (lmic_pins.rst != LMIC_UNUSED_PIN)
|
||||
pinMode(lmic_pins.rst, OUTPUT);
|
||||
|
||||
pinMode(lmic_pins.dio[0], INPUT);
|
||||
if (lmic_pins.dio[1] != LMIC_UNUSED_PIN)
|
||||
pinMode(lmic_pins.dio[1], INPUT);
|
||||
if (lmic_pins.dio[2] != LMIC_UNUSED_PIN)
|
||||
pinMode(lmic_pins.dio[2], INPUT);
|
||||
}
|
||||
|
||||
// val == 1 => tx 1
|
||||
void hal_pin_rxtx (u1_t val) {
|
||||
if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
|
||||
digitalWrite(lmic_pins.rxtx, val);
|
||||
}
|
||||
|
||||
// set radio RST pin to given value (or keep floating!)
|
||||
void hal_pin_rst (u1_t val) {
|
||||
if (lmic_pins.rst == LMIC_UNUSED_PIN)
|
||||
return;
|
||||
|
||||
if(val == 0 || val == 1) { // drive pin
|
||||
pinMode(lmic_pins.rst, OUTPUT);
|
||||
digitalWrite(lmic_pins.rst, val);
|
||||
} else { // keep pin floating
|
||||
pinMode(lmic_pins.rst, INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
static bool dio_states[NUM_DIO] = {0};
|
||||
|
||||
static void hal_io_check() {
|
||||
uint8_t i;
|
||||
for (i = 0; i < NUM_DIO; ++i) {
|
||||
if (lmic_pins.dio[i] == LMIC_UNUSED_PIN)
|
||||
continue;
|
||||
|
||||
if (dio_states[i] != digitalRead(lmic_pins.dio[i])) {
|
||||
dio_states[i] = !dio_states[i];
|
||||
if (dio_states[i])
|
||||
radio_irq_handler(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SPI
|
||||
|
||||
static const SPISettings settings(10E6, MSBFIRST, SPI_MODE0);
|
||||
|
||||
// Initialize SPI, allowing override of default SPI pins on certain boards.
|
||||
static void hal_spi_init () {
|
||||
#if defined(ESP32)
|
||||
// On the ESP32 the default is _use_hw_ss(false),
|
||||
// so we can set the last parameter to anything.
|
||||
SPI.begin(lmic_pins.sck, lmic_pins.miso, lmic_pins.mosi, 0x00);
|
||||
#elif defined(NRF51)
|
||||
SPI.begin(lmic_pins.sck, lmic_pins.mosi, lmic_pins.miso);
|
||||
#else
|
||||
//unknown board, or board without SPI pin select ability
|
||||
SPI.begin();
|
||||
#endif
|
||||
}
|
||||
|
||||
void hal_pin_nss (u1_t val) {
|
||||
if (!val)
|
||||
SPI.beginTransaction(settings);
|
||||
else
|
||||
SPI.endTransaction();
|
||||
|
||||
//Serial.println(val?">>":"<<");
|
||||
digitalWrite(lmic_pins.nss, val);
|
||||
}
|
||||
|
||||
// perform SPI transaction with radio
|
||||
u1_t hal_spi (u1_t out) {
|
||||
u1_t res = SPI.transfer(out);
|
||||
/*
|
||||
Serial.print(">");
|
||||
Serial.print(out, HEX);
|
||||
Serial.print("<");
|
||||
Serial.println(res, HEX);
|
||||
*/
|
||||
return res;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// TIME
|
||||
|
||||
static void hal_time_init () {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
u4_t hal_ticks () {
|
||||
// Because micros() is scaled down in this function, micros() will
|
||||
// overflow before the tick timer should, causing the tick timer to
|
||||
// miss a significant part of its values if not corrected. To fix
|
||||
// this, the "overflow" serves as an overflow area for the micros()
|
||||
// counter. It consists of three parts:
|
||||
// - The US_PER_OSTICK upper bits are effectively an extension for
|
||||
// the micros() counter and are added to the result of this
|
||||
// function.
|
||||
// - The next bit overlaps with the most significant bit of
|
||||
// micros(). This is used to detect micros() overflows.
|
||||
// - The remaining bits are always zero.
|
||||
//
|
||||
// By comparing the overlapping bit with the corresponding bit in
|
||||
// the micros() return value, overflows can be detected and the
|
||||
// upper bits are incremented. This is done using some clever
|
||||
// bitwise operations, to remove the need for comparisons and a
|
||||
// jumps, which should result in efficient code. By avoiding shifts
|
||||
// other than by multiples of 8 as much as possible, this is also
|
||||
// efficient on AVR (which only has 1-bit shifts).
|
||||
static uint8_t overflow = 0;
|
||||
|
||||
// Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0,
|
||||
// the others will be the lower bits of our return value.
|
||||
uint32_t scaled = micros() >> US_PER_OSTICK_EXPONENT;
|
||||
// Most significant byte of scaled
|
||||
uint8_t msb = scaled >> 24;
|
||||
// Mask pointing to the overlapping bit in msb and overflow.
|
||||
const uint8_t mask = (1 << (7 - US_PER_OSTICK_EXPONENT));
|
||||
// Update overflow. If the overlapping bit is different
|
||||
// between overflow and msb, it is added to the stored value,
|
||||
// so the overlapping bit becomes equal again and, if it changed
|
||||
// from 1 to 0, the upper bits are incremented.
|
||||
overflow += (msb ^ overflow) & mask;
|
||||
|
||||
// Return the scaled value with the upper bits of stored added. The
|
||||
// overlapping bit will be equal and the lower bits will be 0, so
|
||||
// bitwise or is a no-op for them.
|
||||
return scaled | ((uint32_t)overflow << 24);
|
||||
|
||||
// 0 leads to correct, but overly complex code (it could just return
|
||||
// micros() unmodified), 8 leaves no room for the overlapping bit.
|
||||
static_assert(US_PER_OSTICK_EXPONENT > 0 && US_PER_OSTICK_EXPONENT < 8, "Invalid US_PER_OSTICK_EXPONENT value");
|
||||
}
|
||||
|
||||
// Returns the number of ticks until time. Negative values indicate that
|
||||
// time has already passed.
|
||||
static s4_t delta_time(u4_t time) {
|
||||
return (s4_t)(time - hal_ticks());
|
||||
}
|
||||
|
||||
void hal_waitUntil (u4_t time) {
|
||||
s4_t delta = delta_time(time);
|
||||
// From delayMicroseconds docs: Currently, the largest value that
|
||||
// will produce an accurate delay is 16383.
|
||||
while (delta > (16000 / US_PER_OSTICK)) {
|
||||
delay(16);
|
||||
delta -= (16000 / US_PER_OSTICK);
|
||||
}
|
||||
if (delta > 0)
|
||||
delayMicroseconds(delta * US_PER_OSTICK);
|
||||
}
|
||||
|
||||
// check and rewind for target time
|
||||
u1_t hal_checkTimer (u4_t time) {
|
||||
// No need to schedule wakeup, since we're not sleeping
|
||||
return delta_time(time) <= 0;
|
||||
}
|
||||
|
||||
static uint8_t irqlevel = 0;
|
||||
|
||||
void hal_disableIRQs () {
|
||||
noInterrupts();
|
||||
irqlevel++;
|
||||
}
|
||||
|
||||
void hal_enableIRQs () {
|
||||
if(--irqlevel == 0) {
|
||||
interrupts();
|
||||
|
||||
// Instead of using proper interrupts (which are a bit tricky
|
||||
// and/or not available on all pins on AVR), just poll the pin
|
||||
// values. Since os_runloop disables and re-enables interrupts,
|
||||
// putting this here makes sure we check at least once every
|
||||
// loop.
|
||||
//
|
||||
// As an additional bonus, this prevents the can of worms that
|
||||
// we would otherwise get for running SPI transfers inside ISRs
|
||||
hal_io_check();
|
||||
}
|
||||
}
|
||||
|
||||
void hal_sleep () {
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if defined(LMIC_PRINTF_TO)
|
||||
static int uart_putchar (char c, FILE *)
|
||||
{
|
||||
LMIC_PRINTF_TO.write(c) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
void hal_printf_init() {
|
||||
// create a FILE structure to reference our UART output function
|
||||
static FILE uartout;
|
||||
memset(&uartout, 0, sizeof(uartout));
|
||||
|
||||
// fill in the UART file descriptor with pointer to writer.
|
||||
fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
||||
|
||||
// The uart is the standard output device STDOUT.
|
||||
stdout = &uartout ;
|
||||
}
|
||||
#endif // defined(LMIC_PRINTF_TO)
|
||||
|
||||
void hal_init () {
|
||||
// configure radio I/O and interrupt handler
|
||||
hal_io_init();
|
||||
// configure radio SPI
|
||||
hal_spi_init();
|
||||
// configure timer and interrupt handler
|
||||
hal_time_init();
|
||||
#if defined(LMIC_PRINTF_TO)
|
||||
// printf support
|
||||
hal_printf_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void hal_failed (const char *file, u2_t line) {
|
||||
#if defined(LMIC_FAILURE_TO)
|
||||
LMIC_FAILURE_TO.println("FAILURE ");
|
||||
LMIC_FAILURE_TO.print(file);
|
||||
LMIC_FAILURE_TO.print(':');
|
||||
LMIC_FAILURE_TO.println(line);
|
||||
LMIC_FAILURE_TO.flush();
|
||||
#endif
|
||||
hal_disableIRQs();
|
||||
while(1);
|
||||
}
|
41
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/hal/hal.h
Normal file
41
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/hal/hal.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Matthijs Kooijman
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* This the HAL to run LMIC on top of the Arduino environment.
|
||||
*******************************************************************************/
|
||||
#ifndef _hal_hal_h_
|
||||
#define _hal_hal_h_
|
||||
|
||||
static const int NUM_DIO = 3;
|
||||
|
||||
#if defined(ESP32) || defined(NRF51)
|
||||
#define LMIC_SPI_PINS_IN_MAPPING
|
||||
struct lmic_pinmap {
|
||||
u1_t mosi;
|
||||
u1_t miso;
|
||||
u1_t sck;
|
||||
u1_t nss;
|
||||
u1_t rxtx;
|
||||
u1_t rst;
|
||||
u1_t dio[NUM_DIO];
|
||||
};
|
||||
#else
|
||||
struct lmic_pinmap {
|
||||
u1_t nss;
|
||||
u1_t rxtx;
|
||||
u1_t rst;
|
||||
u1_t dio[NUM_DIO];
|
||||
};
|
||||
#endif
|
||||
|
||||
// Use this for any unused pins.
|
||||
const u1_t LMIC_UNUSED_PIN = 0xff;
|
||||
|
||||
// Declared here, to be defined an initialized by the application
|
||||
extern const lmic_pinmap lmic_pins;
|
||||
|
||||
#endif // _hal_hal_h_
|
9
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic.h
Normal file
9
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#include "lmic/lmic.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
83
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/config.h
Normal file
83
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/config.h
Normal file
@ -0,0 +1,83 @@
|
||||
#ifndef _lmic_config_h_
|
||||
#define _lmic_config_h_
|
||||
|
||||
// In the original LMIC code, these config values were defined on the
|
||||
// gcc commandline. Since Arduino does not allow easily modifying the
|
||||
// compiler commandline, use this file instead.
|
||||
|
||||
#define CFG_eu868 1
|
||||
//#define CFG_us915 1
|
||||
// This is the SX1272/SX1273 radio, which is also used on the HopeRF
|
||||
// RFM92 boards.
|
||||
//#define CFG_sx1272_radio 1
|
||||
// This is the SX1276/SX1277/SX1278/SX1279 radio, which is also used on
|
||||
// the HopeRF RFM95 boards.
|
||||
#define CFG_sx1276_radio 1
|
||||
|
||||
// 16 μs per tick
|
||||
// LMIC requires ticks to be 15.5μs - 100 μs long
|
||||
#define US_PER_OSTICK_EXPONENT 4
|
||||
#define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT)
|
||||
#define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK)
|
||||
|
||||
// Set this to 1 to enable some basic debug output (using printf) about
|
||||
// RF settings used during transmission and reception. Set to 2 to
|
||||
// enable more verbose output. Make sure that printf is actually
|
||||
// configured (e.g. on AVR it is not by default), otherwise using it can
|
||||
// cause crashing.
|
||||
#define LMIC_DEBUG_LEVEL 0
|
||||
|
||||
// Enable this to allow using printf() to print to the given serial port
|
||||
// (or any other Print object). This can be easy for debugging. The
|
||||
// current implementation only works on AVR, though.
|
||||
//#define LMIC_PRINTF_TO Serial
|
||||
|
||||
// Any runtime assertion failures are printed to this serial port (or
|
||||
// any other Print object). If this is unset, any failures just silently
|
||||
// halt execution.
|
||||
#define LMIC_FAILURE_TO Serial
|
||||
|
||||
// Uncomment this to disable all code related to joining
|
||||
//#define DISABLE_JOIN
|
||||
// Uncomment this to disable all code related to ping
|
||||
//#define DISABLE_PING
|
||||
// Uncomment this to disable all code related to beacon tracking.
|
||||
// Requires ping to be disabled too
|
||||
//#define DISABLE_BEACONS
|
||||
|
||||
// Uncomment these to disable the corresponding MAC commands.
|
||||
// Class A
|
||||
//#define DISABLE_MCMD_DCAP_REQ // duty cycle cap
|
||||
//#define DISABLE_MCMD_DN2P_SET // 2nd DN window param
|
||||
//#define DISABLE_MCMD_SNCH_REQ // set new channel
|
||||
// Class B
|
||||
//#define DISABLE_MCMD_PING_SET // set ping freq, automatically disabled by DISABLE_PING
|
||||
//#define DISABLE_MCMD_BCNI_ANS // next beacon start, automatical disabled by DISABLE_BEACON
|
||||
|
||||
// In LoRaWAN, a gateway applies I/Q inversion on TX, and nodes do the
|
||||
// same on RX. This ensures that gateways can talk to nodes and vice
|
||||
// versa, but gateways will not hear other gateways and nodes will not
|
||||
// hear other nodes. By uncommenting this macro, this inversion is
|
||||
// disabled and this node can hear other nodes. If two nodes both have
|
||||
// this macro set, they can talk to each other (but they can no longer
|
||||
// hear gateways). This should probably only be used when debugging
|
||||
// and/or when talking to the radio directly (e.g. like in the "raw"
|
||||
// example).
|
||||
//#define DISABLE_INVERT_IQ_ON_RX
|
||||
|
||||
// This allows choosing between multiple included AES implementations.
|
||||
// Make sure exactly one of these is uncommented.
|
||||
//
|
||||
// This selects the original AES implementation included LMIC. This
|
||||
// implementation is optimized for speed on 32-bit processors using
|
||||
// fairly big lookup tables, but it takes up big amounts of flash on the
|
||||
// AVR architecture.
|
||||
// #define USE_ORIGINAL_AES
|
||||
//
|
||||
// This selects the AES implementation written by Ideetroon for their
|
||||
// own LoRaWAN library. It also uses lookup tables, but smaller
|
||||
// byte-oriented ones, making it use a lot less flash space (but it is
|
||||
// also about twice as slow as the original).
|
||||
#define USE_IDEETRON_AES
|
||||
|
||||
#endif // _lmic_config_h_
|
91
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/hal.h
Normal file
91
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/hal.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014-2015 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Zurich Research Lab - initial API, implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _hal_hpp_
|
||||
#define _hal_hpp_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
/*
|
||||
* initialize hardware (IO, SPI, TIMER, IRQ).
|
||||
*/
|
||||
void hal_init (void);
|
||||
|
||||
/*
|
||||
* drive radio NSS pin (0=low, 1=high).
|
||||
*/
|
||||
void hal_pin_nss (u1_t val);
|
||||
|
||||
/*
|
||||
* drive radio RX/TX pins (0=rx, 1=tx).
|
||||
*/
|
||||
void hal_pin_rxtx (u1_t val);
|
||||
|
||||
/*
|
||||
* control radio RST pin (0=low, 1=high, 2=floating)
|
||||
*/
|
||||
void hal_pin_rst (u1_t val);
|
||||
|
||||
/*
|
||||
* perform 8-bit SPI transaction with radio.
|
||||
* - write given byte 'outval'
|
||||
* - read byte and return value
|
||||
*/
|
||||
u1_t hal_spi (u1_t outval);
|
||||
|
||||
/*
|
||||
* disable all CPU interrupts.
|
||||
* - might be invoked nested
|
||||
* - will be followed by matching call to hal_enableIRQs()
|
||||
*/
|
||||
void hal_disableIRQs (void);
|
||||
|
||||
/*
|
||||
* enable CPU interrupts.
|
||||
*/
|
||||
void hal_enableIRQs (void);
|
||||
|
||||
/*
|
||||
* put system and CPU in low-power mode, sleep until interrupt.
|
||||
*/
|
||||
void hal_sleep (void);
|
||||
|
||||
/*
|
||||
* return 32-bit system time in ticks.
|
||||
*/
|
||||
u4_t hal_ticks (void);
|
||||
|
||||
/*
|
||||
* busy-wait until specified timestamp (in ticks) is reached.
|
||||
*/
|
||||
void hal_waitUntil (u4_t time);
|
||||
|
||||
/*
|
||||
* check and rewind timer for target time.
|
||||
* - return 1 if target time is close
|
||||
* - otherwise rewind timer for target time or full period and return 0
|
||||
*/
|
||||
u1_t hal_checkTimer (u4_t targettime);
|
||||
|
||||
/*
|
||||
* perform fatal failure action.
|
||||
* - called by assertions
|
||||
* - action could be HALT or reboot
|
||||
*/
|
||||
void hal_failed (const char *file, u2_t line);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _hal_hpp_
|
2382
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/lmic.c
Normal file
2382
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/lmic.c
Normal file
File diff suppressed because it is too large
Load Diff
320
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/lmic.h
Normal file
320
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/lmic.h
Normal file
@ -0,0 +1,320 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014-2015 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Zurich Research Lab - initial API, implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
//! @file
|
||||
//! @brief LMIC API
|
||||
|
||||
#ifndef _lmic_h_
|
||||
#define _lmic_h_
|
||||
|
||||
#include "oslmic.h"
|
||||
#include "lorabase.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
// LMIC version
|
||||
#define LMIC_VERSION_MAJOR 1
|
||||
#define LMIC_VERSION_MINOR 5
|
||||
#define LMIC_VERSION_BUILD 1431528305
|
||||
|
||||
enum { MAX_FRAME_LEN = 64 }; //!< Library cap on max frame length
|
||||
enum { TXCONF_ATTEMPTS = 8 }; //!< Transmit attempts for confirmed frames
|
||||
enum { MAX_MISSED_BCNS = 20 }; // threshold for triggering rejoin requests
|
||||
enum { MAX_RXSYMS = 100 }; // stop tracking beacon beyond this
|
||||
|
||||
enum { LINK_CHECK_CONT = 12 , // continue with this after reported dead link
|
||||
LINK_CHECK_DEAD = 24 , // after this UP frames and no response from NWK assume link is dead
|
||||
LINK_CHECK_INIT = -12 , // UP frame count until we inc datarate
|
||||
LINK_CHECK_OFF =-128 }; // link check disabled
|
||||
|
||||
enum { TIME_RESYNC = 6*128 }; // secs
|
||||
enum { TXRX_GUARD_ms = 6000 }; // msecs - don't start TX-RX transaction before beacon
|
||||
enum { JOIN_GUARD_ms = 9000 }; // msecs - don't start Join Req/Acc transaction before beacon
|
||||
enum { TXRX_BCNEXT_secs = 2 }; // secs - earliest start after beacon time
|
||||
enum { RETRY_PERIOD_secs = 3 }; // secs - random period for retrying a confirmed send
|
||||
|
||||
#if defined(CFG_eu868) // EU868 spectrum ====================================================
|
||||
|
||||
enum { MAX_CHANNELS = 16 }; //!< Max supported channels
|
||||
enum { MAX_BANDS = 4 };
|
||||
|
||||
enum { LIMIT_CHANNELS = (1<<4) }; // EU868 will never have more channels
|
||||
//! \internal
|
||||
struct band_t {
|
||||
u2_t txcap; // duty cycle limitation: 1/txcap
|
||||
s1_t txpow; // maximum TX power
|
||||
u1_t lastchnl; // last used channel
|
||||
ostime_t avail; // channel is blocked until this time
|
||||
};
|
||||
TYPEDEF_xref2band_t; //!< \internal
|
||||
|
||||
#elif defined(CFG_us915) // US915 spectrum =================================================
|
||||
|
||||
enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable
|
||||
enum { MAX_TXPOW_125kHz = 30 };
|
||||
|
||||
#endif // ==========================================================================
|
||||
|
||||
// Keep in sync with evdefs.hpp::drChange
|
||||
enum { DRCHG_SET, DRCHG_NOJACC, DRCHG_NOACK, DRCHG_NOADRACK, DRCHG_NWKCMD };
|
||||
enum { KEEP_TXPOW = -128 };
|
||||
|
||||
|
||||
#if !defined(DISABLE_PING)
|
||||
//! \internal
|
||||
struct rxsched_t {
|
||||
u1_t dr;
|
||||
u1_t intvExp; // 0..7
|
||||
u1_t slot; // runs from 0 to 128
|
||||
u1_t rxsyms;
|
||||
ostime_t rxbase;
|
||||
ostime_t rxtime; // start of next spot
|
||||
u4_t freq;
|
||||
};
|
||||
TYPEDEF_xref2rxsched_t; //!< \internal
|
||||
#endif // !DISABLE_PING
|
||||
|
||||
|
||||
#if !defined(DISABLE_BEACONS)
|
||||
//! Parsing and tracking states of beacons.
|
||||
enum { BCN_NONE = 0x00, //!< No beacon received
|
||||
BCN_PARTIAL = 0x01, //!< Only first (common) part could be decoded (info,lat,lon invalid/previous)
|
||||
BCN_FULL = 0x02, //!< Full beacon decoded
|
||||
BCN_NODRIFT = 0x04, //!< No drift value measured yet
|
||||
BCN_NODDIFF = 0x08 }; //!< No differential drift measured yet
|
||||
//! Information about the last and previous beacons.
|
||||
struct bcninfo_t {
|
||||
ostime_t txtime; //!< Time when the beacon was sent
|
||||
s1_t rssi; //!< Adjusted RSSI value of last received beacon
|
||||
s1_t snr; //!< Scaled SNR value of last received beacon
|
||||
u1_t flags; //!< Last beacon reception and tracking states. See BCN_* values.
|
||||
u4_t time; //!< GPS time in seconds of last beacon (received or surrogate)
|
||||
//
|
||||
u1_t info; //!< Info field of last beacon (valid only if BCN_FULL set)
|
||||
s4_t lat; //!< Lat field of last beacon (valid only if BCN_FULL set)
|
||||
s4_t lon; //!< Lon field of last beacon (valid only if BCN_FULL set)
|
||||
};
|
||||
#endif // !DISABLE_BEACONS
|
||||
|
||||
// purpose of receive window - lmic_t.rxState
|
||||
enum { RADIO_RST=0, RADIO_TX=1, RADIO_RX=2, RADIO_RXON=3 };
|
||||
// Netid values / lmic_t.netid
|
||||
enum { NETID_NONE=(int)~0U, NETID_MASK=(int)0xFFFFFF };
|
||||
// MAC operation modes (lmic_t.opmode).
|
||||
enum { OP_NONE = 0x0000,
|
||||
OP_SCAN = 0x0001, // radio scan to find a beacon
|
||||
OP_TRACK = 0x0002, // track my networks beacon (netid)
|
||||
OP_JOINING = 0x0004, // device joining in progress (blocks other activities)
|
||||
OP_TXDATA = 0x0008, // TX user data (buffered in pendTxData)
|
||||
OP_POLL = 0x0010, // send empty UP frame to ACK confirmed DN/fetch more DN data
|
||||
OP_REJOIN = 0x0020, // occasionally send JOIN REQUEST
|
||||
OP_SHUTDOWN = 0x0040, // prevent MAC from doing anything
|
||||
OP_TXRXPEND = 0x0080, // TX/RX transaction pending
|
||||
OP_RNDTX = 0x0100, // prevent TX lining up after a beacon
|
||||
OP_PINGINI = 0x0200, // pingable is initialized and scheduling active
|
||||
OP_PINGABLE = 0x0400, // we're pingable
|
||||
OP_NEXTCHNL = 0x0800, // find a new channel
|
||||
OP_LINKDEAD = 0x1000, // link was reported as dead
|
||||
OP_TESTMODE = 0x2000, // developer test mode
|
||||
};
|
||||
// TX-RX transaction flags - report back to user
|
||||
enum { TXRX_ACK = 0x80, // confirmed UP frame was acked
|
||||
TXRX_NACK = 0x40, // confirmed UP frame was not acked
|
||||
TXRX_NOPORT = 0x20, // set if a frame with a port was RXed, clr if no frame/no port
|
||||
TXRX_PORT = 0x10, // set if a frame with a port was RXed, LMIC.frame[LMIC.dataBeg-1] => port
|
||||
TXRX_DNW1 = 0x01, // received in 1st DN slot
|
||||
TXRX_DNW2 = 0x02, // received in 2dn DN slot
|
||||
TXRX_PING = 0x04 }; // received in a scheduled RX slot
|
||||
// Event types for event callback
|
||||
enum _ev_t { EV_SCAN_TIMEOUT=1, EV_BEACON_FOUND,
|
||||
EV_BEACON_MISSED, EV_BEACON_TRACKED, EV_JOINING,
|
||||
EV_JOINED, EV_RFU1, EV_JOIN_FAILED, EV_REJOIN_FAILED,
|
||||
EV_TXCOMPLETE, EV_LOST_TSYNC, EV_RESET,
|
||||
EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE };
|
||||
typedef enum _ev_t ev_t;
|
||||
|
||||
enum {
|
||||
// This value represents 100% error in LMIC.clockError
|
||||
MAX_CLOCK_ERROR = 65536,
|
||||
};
|
||||
|
||||
struct lmic_t {
|
||||
// Radio settings TX/RX (also accessed by HAL)
|
||||
ostime_t txend;
|
||||
ostime_t rxtime;
|
||||
u4_t freq;
|
||||
s1_t rssi;
|
||||
s1_t snr;
|
||||
rps_t rps;
|
||||
u1_t rxsyms;
|
||||
u1_t dndr;
|
||||
s1_t txpow; // dBm
|
||||
|
||||
osjob_t osjob;
|
||||
|
||||
// Channel scheduling
|
||||
#if defined(CFG_eu868)
|
||||
band_t bands[MAX_BANDS];
|
||||
u4_t channelFreq[MAX_CHANNELS];
|
||||
u2_t channelDrMap[MAX_CHANNELS];
|
||||
u2_t channelMap;
|
||||
#elif defined(CFG_us915)
|
||||
u4_t xchFreq[MAX_XCHANNELS]; // extra channel frequencies (if device is behind a repeater)
|
||||
u2_t xchDrMap[MAX_XCHANNELS]; // extra channel datarate ranges ---XXX: ditto
|
||||
u2_t channelMap[(72+MAX_XCHANNELS+15)/16]; // enabled bits
|
||||
u2_t chRnd; // channel randomizer
|
||||
#endif
|
||||
u1_t txChnl; // channel for next TX
|
||||
u1_t globalDutyRate; // max rate: 1/2^k
|
||||
ostime_t globalDutyAvail; // time device can send again
|
||||
|
||||
u4_t netid; // current network id (~0 - none)
|
||||
u2_t opmode;
|
||||
u1_t upRepeat; // configured up repeat
|
||||
s1_t adrTxPow; // ADR adjusted TX power
|
||||
u1_t datarate; // current data rate
|
||||
u1_t errcr; // error coding rate (used for TX only)
|
||||
u1_t rejoinCnt; // adjustment for rejoin datarate
|
||||
#if !defined(DISABLE_BEACONS)
|
||||
s2_t drift; // last measured drift
|
||||
s2_t lastDriftDiff;
|
||||
s2_t maxDriftDiff;
|
||||
#endif
|
||||
|
||||
u2_t clockError; // Inaccuracy in the clock. CLOCK_ERROR_MAX
|
||||
// represents +/-100% error
|
||||
|
||||
u1_t pendTxPort;
|
||||
u1_t pendTxConf; // confirmed data
|
||||
u1_t pendTxLen; // +0x80 = confirmed
|
||||
u1_t pendTxData[MAX_LEN_PAYLOAD];
|
||||
|
||||
u2_t devNonce; // last generated nonce
|
||||
u1_t nwkKey[16]; // network session key
|
||||
u1_t artKey[16]; // application router session key
|
||||
devaddr_t devaddr;
|
||||
u4_t seqnoDn; // device level down stream seqno
|
||||
u4_t seqnoUp;
|
||||
|
||||
u1_t dnConf; // dn frame confirm pending: LORA::FCT_ACK or 0
|
||||
s1_t adrAckReq; // counter until we reset data rate (0=off)
|
||||
u1_t adrChanged;
|
||||
|
||||
u1_t rxDelay; // Rx delay after TX
|
||||
|
||||
u1_t margin;
|
||||
bit_t ladrAns; // link adr adapt answer pending
|
||||
bit_t devsAns; // device status answer pending
|
||||
u1_t adrEnabled;
|
||||
u1_t moreData; // NWK has more data pending
|
||||
#if !defined(DISABLE_MCMD_DCAP_REQ)
|
||||
bit_t dutyCapAns; // have to ACK duty cycle settings
|
||||
#endif
|
||||
#if !defined(DISABLE_MCMD_SNCH_REQ)
|
||||
u1_t snchAns; // answer set new channel
|
||||
#endif
|
||||
// 2nd RX window (after up stream)
|
||||
u1_t dn2Dr;
|
||||
u4_t dn2Freq;
|
||||
#if !defined(DISABLE_MCMD_DN2P_SET)
|
||||
u1_t dn2Ans; // 0=no answer pend, 0x80+ACKs
|
||||
#endif
|
||||
|
||||
// Class B state
|
||||
#if !defined(DISABLE_BEACONS)
|
||||
u1_t missedBcns; // unable to track last N beacons
|
||||
u1_t bcninfoTries; // how often to try (scan mode only)
|
||||
#endif
|
||||
#if !defined(DISABLE_MCMD_PING_SET) && !defined(DISABLE_PING)
|
||||
u1_t pingSetAns; // answer set cmd and ACK bits
|
||||
#endif
|
||||
#if !defined(DISABLE_PING)
|
||||
rxsched_t ping; // pingable setup
|
||||
#endif
|
||||
|
||||
// Public part of MAC state
|
||||
u1_t txCnt;
|
||||
u1_t txrxFlags; // transaction flags (TX-RX combo)
|
||||
u1_t dataBeg; // 0 or start of data (dataBeg-1 is port)
|
||||
u1_t dataLen; // 0 no data or zero length data, >0 byte count of data
|
||||
u1_t frame[MAX_LEN_FRAME];
|
||||
|
||||
#if !defined(DISABLE_BEACONS)
|
||||
u1_t bcnChnl;
|
||||
u1_t bcnRxsyms; //
|
||||
ostime_t bcnRxtime;
|
||||
bcninfo_t bcninfo; // Last received beacon info
|
||||
#endif
|
||||
};
|
||||
//! \var struct lmic_t LMIC
|
||||
//! The state of LMIC MAC layer is encapsulated in this variable.
|
||||
DECLARE_LMIC; //!< \internal
|
||||
|
||||
//! Construct a bit map of allowed datarates from drlo to drhi (both included).
|
||||
#define DR_RANGE_MAP(drlo,drhi) (((u2_t)0xFFFF<<(drlo)) & ((u2_t)0xFFFF>>(15-(drhi))))
|
||||
#if defined(CFG_eu868)
|
||||
enum { BAND_MILLI=0, BAND_CENTI=1, BAND_DECI=2, BAND_AUX=3 };
|
||||
bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap);
|
||||
#endif
|
||||
bit_t LMIC_setupChannel (u1_t channel, u4_t freq, u2_t drmap, s1_t band);
|
||||
void LMIC_disableChannel (u1_t channel);
|
||||
#if defined(CFG_us915)
|
||||
void LMIC_enableChannel (u1_t channel);
|
||||
void LMIC_enableSubBand (u1_t band);
|
||||
void LMIC_disableSubBand (u1_t band);
|
||||
void LMIC_selectSubBand (u1_t band);
|
||||
#endif
|
||||
|
||||
void LMIC_setDrTxpow (dr_t dr, s1_t txpow); // set default/start DR/txpow
|
||||
void LMIC_setAdrMode (bit_t enabled); // set ADR mode (if mobile turn off)
|
||||
#if !defined(DISABLE_JOIN)
|
||||
bit_t LMIC_startJoining (void);
|
||||
#endif
|
||||
|
||||
void LMIC_shutdown (void);
|
||||
void LMIC_init (void);
|
||||
void LMIC_reset (void);
|
||||
void LMIC_clrTxData (void);
|
||||
void LMIC_setTxData (void);
|
||||
int LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed);
|
||||
void LMIC_sendAlive (void);
|
||||
|
||||
#if !defined(DISABLE_BEACONS)
|
||||
bit_t LMIC_enableTracking (u1_t tryBcnInfo);
|
||||
void LMIC_disableTracking (void);
|
||||
#endif
|
||||
|
||||
#if !defined(DISABLE_PING)
|
||||
void LMIC_stopPingable (void);
|
||||
void LMIC_setPingable (u1_t intvExp);
|
||||
#endif
|
||||
#if !defined(DISABLE_JOIN)
|
||||
void LMIC_tryRejoin (void);
|
||||
#endif
|
||||
|
||||
void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey);
|
||||
void LMIC_setLinkCheckMode (bit_t enabled);
|
||||
void LMIC_setClockError(u2_t error);
|
||||
|
||||
// Declare onEvent() function, to make sure any definition will have the
|
||||
// C conventions, even when in a C++ file.
|
||||
DECL_ON_LMIC_EVENT;
|
||||
|
||||
// Special APIs - for development or testing
|
||||
// !!!See implementation for caveats!!!
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _lmic_h_
|
391
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/lorabase.h
Normal file
391
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/lorabase.h
Normal file
@ -0,0 +1,391 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014-2015 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Zurich Research Lab - initial API, implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _lorabase_h_
|
||||
#define _lorabase_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
// ================================================================================
|
||||
// BEG: Keep in sync with lorabase.hpp
|
||||
//
|
||||
|
||||
enum _cr_t { CR_4_5=0, CR_4_6, CR_4_7, CR_4_8 };
|
||||
enum _sf_t { FSK=0, SF7, SF8, SF9, SF10, SF11, SF12, SFrfu };
|
||||
enum _bw_t { BW125=0, BW250, BW500, BWrfu };
|
||||
typedef u1_t cr_t;
|
||||
typedef u1_t sf_t;
|
||||
typedef u1_t bw_t;
|
||||
typedef u1_t dr_t;
|
||||
// Radio parameter set (encodes SF/BW/CR/IH/NOCRC)
|
||||
typedef u2_t rps_t;
|
||||
TYPEDEF_xref2rps_t;
|
||||
|
||||
enum { ILLEGAL_RPS = 0xFF };
|
||||
enum { DR_PAGE_EU868 = 0x00 };
|
||||
enum { DR_PAGE_US915 = 0x10 };
|
||||
|
||||
// Global maximum frame length
|
||||
enum { STD_PREAMBLE_LEN = 8 };
|
||||
enum { MAX_LEN_FRAME = 64 };
|
||||
enum { LEN_DEVNONCE = 2 };
|
||||
enum { LEN_ARTNONCE = 3 };
|
||||
enum { LEN_NETID = 3 };
|
||||
enum { DELAY_JACC1 = 5 }; // in secs
|
||||
enum { DELAY_DNW1 = 1 }; // in secs down window #1
|
||||
enum { DELAY_EXTDNW2 = 1 }; // in secs
|
||||
enum { DELAY_JACC2 = DELAY_JACC1+(int)DELAY_EXTDNW2 }; // in secs
|
||||
enum { DELAY_DNW2 = DELAY_DNW1 +(int)DELAY_EXTDNW2 }; // in secs down window #1
|
||||
enum { BCN_INTV_exp = 7 };
|
||||
enum { BCN_INTV_sec = 1<<BCN_INTV_exp };
|
||||
enum { BCN_INTV_ms = BCN_INTV_sec*1000L };
|
||||
enum { BCN_INTV_us = BCN_INTV_ms*1000L };
|
||||
enum { BCN_RESERVE_ms = 2120 }; // space reserved for beacon and NWK management
|
||||
enum { BCN_GUARD_ms = 3000 }; // end of beacon period to prevent interference with beacon
|
||||
enum { BCN_SLOT_SPAN_ms = 30 }; // 2^12 reception slots a this span
|
||||
enum { BCN_WINDOW_ms = BCN_INTV_ms-(int)BCN_GUARD_ms-(int)BCN_RESERVE_ms };
|
||||
enum { BCN_RESERVE_us = 2120000 };
|
||||
enum { BCN_GUARD_us = 3000000 };
|
||||
enum { BCN_SLOT_SPAN_us = 30000 };
|
||||
|
||||
#if defined(CFG_eu868) // ==============================================
|
||||
|
||||
enum _dr_eu868_t { DR_SF12=0, DR_SF11, DR_SF10, DR_SF9, DR_SF8, DR_SF7, DR_SF7B, DR_FSK, DR_NONE };
|
||||
enum { DR_DFLTMIN = DR_SF7 };
|
||||
enum { DR_PAGE = DR_PAGE_EU868 };
|
||||
|
||||
// Default frequency plan for EU 868MHz ISM band
|
||||
// Bands:
|
||||
// g1 : 1% 14dBm
|
||||
// g2 : 0.1% 14dBm
|
||||
// g3 : 10% 27dBm
|
||||
// freq band datarates
|
||||
enum { EU868_F1 = 868100000, // g1 SF7-12
|
||||
EU868_F2 = 868300000, // g1 SF7-12 FSK SF7/250
|
||||
EU868_F3 = 868500000, // g1 SF7-12
|
||||
EU868_F4 = 868850000, // g2 SF7-12
|
||||
EU868_F5 = 869050000, // g2 SF7-12
|
||||
EU868_F6 = 869525000, // g3 SF7-12
|
||||
EU868_J4 = 864100000, // g2 SF7-12 used during join
|
||||
EU868_J5 = 864300000, // g2 SF7-12 ditto
|
||||
EU868_J6 = 864500000, // g2 SF7-12 ditto
|
||||
};
|
||||
enum { EU868_FREQ_MIN = 863000000,
|
||||
EU868_FREQ_MAX = 870000000 };
|
||||
|
||||
enum { CHNL_PING = 5 };
|
||||
enum { FREQ_PING = EU868_F6 }; // default ping freq
|
||||
enum { DR_PING = DR_SF9 }; // default ping DR
|
||||
enum { CHNL_DNW2 = 5 };
|
||||
enum { FREQ_DNW2 = EU868_F6 };
|
||||
enum { DR_DNW2 = DR_SF12 };
|
||||
enum { CHNL_BCN = 5 };
|
||||
enum { FREQ_BCN = EU868_F6 };
|
||||
enum { DR_BCN = DR_SF9 };
|
||||
enum { AIRTIME_BCN = 144384 }; // micros
|
||||
|
||||
enum {
|
||||
// Beacon frame format EU SF9
|
||||
OFF_BCN_NETID = 0,
|
||||
OFF_BCN_TIME = 3,
|
||||
OFF_BCN_CRC1 = 7,
|
||||
OFF_BCN_INFO = 8,
|
||||
OFF_BCN_LAT = 9,
|
||||
OFF_BCN_LON = 12,
|
||||
OFF_BCN_CRC2 = 15,
|
||||
LEN_BCN = 17
|
||||
};
|
||||
|
||||
#elif defined(CFG_us915) // =========================================
|
||||
|
||||
enum _dr_us915_t { DR_SF10=0, DR_SF9, DR_SF8, DR_SF7, DR_SF8C, DR_NONE,
|
||||
// Devices behind a router:
|
||||
DR_SF12CR=8, DR_SF11CR, DR_SF10CR, DR_SF9CR, DR_SF8CR, DR_SF7CR };
|
||||
enum { DR_DFLTMIN = DR_SF8C };
|
||||
enum { DR_PAGE = DR_PAGE_US915 };
|
||||
|
||||
// Default frequency plan for US 915MHz
|
||||
enum { US915_125kHz_UPFBASE = 902300000,
|
||||
US915_125kHz_UPFSTEP = 200000,
|
||||
US915_500kHz_UPFBASE = 903000000,
|
||||
US915_500kHz_UPFSTEP = 1600000,
|
||||
US915_500kHz_DNFBASE = 923300000,
|
||||
US915_500kHz_DNFSTEP = 600000
|
||||
};
|
||||
enum { US915_FREQ_MIN = 902000000,
|
||||
US915_FREQ_MAX = 928000000 };
|
||||
|
||||
enum { CHNL_PING = 0 }; // used only for default init of state (follows beacon - rotating)
|
||||
enum { FREQ_PING = US915_500kHz_DNFBASE + CHNL_PING*US915_500kHz_DNFSTEP }; // default ping freq
|
||||
enum { DR_PING = DR_SF10CR }; // default ping DR
|
||||
enum { CHNL_DNW2 = 0 };
|
||||
enum { FREQ_DNW2 = US915_500kHz_DNFBASE + CHNL_DNW2*US915_500kHz_DNFSTEP };
|
||||
enum { DR_DNW2 = DR_SF12CR };
|
||||
enum { CHNL_BCN = 0 }; // used only for default init of state (rotating beacon scheme)
|
||||
enum { DR_BCN = DR_SF10CR };
|
||||
enum { AIRTIME_BCN = 72192 }; // micros
|
||||
|
||||
enum {
|
||||
// Beacon frame format US SF10
|
||||
OFF_BCN_NETID = 0,
|
||||
OFF_BCN_TIME = 3,
|
||||
OFF_BCN_CRC1 = 7,
|
||||
OFF_BCN_INFO = 9,
|
||||
OFF_BCN_LAT = 10,
|
||||
OFF_BCN_LON = 13,
|
||||
OFF_BCN_RFU1 = 16,
|
||||
OFF_BCN_CRC2 = 17,
|
||||
LEN_BCN = 19
|
||||
};
|
||||
|
||||
#endif // ===================================================
|
||||
|
||||
enum {
|
||||
// Join Request frame format
|
||||
OFF_JR_HDR = 0,
|
||||
OFF_JR_ARTEUI = 1,
|
||||
OFF_JR_DEVEUI = 9,
|
||||
OFF_JR_DEVNONCE = 17,
|
||||
OFF_JR_MIC = 19,
|
||||
LEN_JR = 23
|
||||
};
|
||||
enum {
|
||||
// Join Accept frame format
|
||||
OFF_JA_HDR = 0,
|
||||
OFF_JA_ARTNONCE = 1,
|
||||
OFF_JA_NETID = 4,
|
||||
OFF_JA_DEVADDR = 7,
|
||||
OFF_JA_RFU = 11,
|
||||
OFF_JA_DLSET = 11,
|
||||
OFF_JA_RXDLY = 12,
|
||||
OFF_CFLIST = 13,
|
||||
LEN_JA = 17,
|
||||
LEN_JAEXT = 17+16
|
||||
};
|
||||
enum {
|
||||
// Data frame format
|
||||
OFF_DAT_HDR = 0,
|
||||
OFF_DAT_ADDR = 1,
|
||||
OFF_DAT_FCT = 5,
|
||||
OFF_DAT_SEQNO = 6,
|
||||
OFF_DAT_OPTS = 8,
|
||||
};
|
||||
enum { MAX_LEN_PAYLOAD = MAX_LEN_FRAME-(int)OFF_DAT_OPTS-4 };
|
||||
enum {
|
||||
// Bitfields in frame format octet
|
||||
HDR_FTYPE = 0xE0,
|
||||
HDR_RFU = 0x1C,
|
||||
HDR_MAJOR = 0x03
|
||||
};
|
||||
enum { HDR_FTYPE_DNFLAG = 0x20 }; // flags DN frame except for HDR_FTYPE_PROP
|
||||
enum {
|
||||
// Values of frame type bit field
|
||||
HDR_FTYPE_JREQ = 0x00,
|
||||
HDR_FTYPE_JACC = 0x20,
|
||||
HDR_FTYPE_DAUP = 0x40, // data (unconfirmed) up
|
||||
HDR_FTYPE_DADN = 0x60, // data (unconfirmed) dn
|
||||
HDR_FTYPE_DCUP = 0x80, // data confirmed up
|
||||
HDR_FTYPE_DCDN = 0xA0, // data confirmed dn
|
||||
HDR_FTYPE_REJOIN = 0xC0, // rejoin for roaming
|
||||
HDR_FTYPE_PROP = 0xE0
|
||||
};
|
||||
enum {
|
||||
HDR_MAJOR_V1 = 0x00,
|
||||
};
|
||||
enum {
|
||||
// Bitfields in frame control octet
|
||||
FCT_ADREN = 0x80,
|
||||
FCT_ADRARQ = 0x40,
|
||||
FCT_ACK = 0x20,
|
||||
FCT_MORE = 0x10, // also in DN direction: Class B indicator
|
||||
FCT_OPTLEN = 0x0F,
|
||||
};
|
||||
enum {
|
||||
// In UP direction: signals class B enabled
|
||||
FCT_CLASSB = FCT_MORE
|
||||
};
|
||||
enum {
|
||||
NWKID_MASK = (int)0xFE000000,
|
||||
NWKID_BITS = 7
|
||||
};
|
||||
|
||||
// MAC uplink commands downwlink too
|
||||
enum {
|
||||
// Class A
|
||||
MCMD_LCHK_REQ = 0x02, // - link check request : -
|
||||
MCMD_LADR_ANS = 0x03, // - link ADR answer : u1:7-3:RFU, 3/2/1: pow/DR/Ch ACK
|
||||
MCMD_DCAP_ANS = 0x04, // - duty cycle answer : -
|
||||
MCMD_DN2P_ANS = 0x05, // - 2nd DN slot status : u1:7-2:RFU 1/0:datarate/channel ack
|
||||
MCMD_DEVS_ANS = 0x06, // - device status ans : u1:battery 0,1-254,255=?, u1:7-6:RFU,5-0:margin(-32..31)
|
||||
MCMD_SNCH_ANS = 0x07, // - set new channel : u1: 7-2=RFU, 1/0:DR/freq ACK
|
||||
// Class B
|
||||
MCMD_PING_IND = 0x10, // - pingability indic : u1: 7=RFU, 6-4:interval, 3-0:datarate
|
||||
MCMD_PING_ANS = 0x11, // - ack ping freq : u1: 7-1:RFU, 0:freq ok
|
||||
MCMD_BCNI_REQ = 0x12, // - next beacon start : -
|
||||
};
|
||||
|
||||
// MAC downlink commands
|
||||
enum {
|
||||
// Class A
|
||||
MCMD_LCHK_ANS = 0x02, // link check answer : u1:margin 0-254,255=unknown margin / u1:gwcnt
|
||||
MCMD_LADR_REQ = 0x03, // link ADR request : u1:DR/TXPow, u2:chmask, u1:chpage/repeat
|
||||
MCMD_DCAP_REQ = 0x04, // duty cycle cap : u1:255 dead [7-4]:RFU, [3-0]:cap 2^-k
|
||||
MCMD_DN2P_SET = 0x05, // 2nd DN window param: u1:7-4:RFU/3-0:datarate, u3:freq
|
||||
MCMD_DEVS_REQ = 0x06, // device status req : -
|
||||
MCMD_SNCH_REQ = 0x07, // set new channel : u1:chidx, u3:freq, u1:DRrange
|
||||
// Class B
|
||||
MCMD_PING_SET = 0x11, // set ping freq : u3: freq
|
||||
MCMD_BCNI_ANS = 0x12, // next beacon start : u2: delay(in TUNIT millis), u1:channel
|
||||
};
|
||||
|
||||
enum {
|
||||
MCMD_BCNI_TUNIT = 30 // time unit of delay value in millis
|
||||
};
|
||||
enum {
|
||||
MCMD_LADR_ANS_RFU = 0xF8, // RFU bits
|
||||
MCMD_LADR_ANS_POWACK = 0x04, // 0=not supported power level
|
||||
MCMD_LADR_ANS_DRACK = 0x02, // 0=unknown data rate
|
||||
MCMD_LADR_ANS_CHACK = 0x01, // 0=unknown channel enabled
|
||||
};
|
||||
enum {
|
||||
MCMD_DN2P_ANS_RFU = 0xFC, // RFU bits
|
||||
MCMD_DN2P_ANS_DRACK = 0x02, // 0=unknown data rate
|
||||
MCMD_DN2P_ANS_CHACK = 0x01, // 0=unknown channel enabled
|
||||
};
|
||||
enum {
|
||||
MCMD_SNCH_ANS_RFU = 0xFC, // RFU bits
|
||||
MCMD_SNCH_ANS_DRACK = 0x02, // 0=unknown data rate
|
||||
MCMD_SNCH_ANS_FQACK = 0x01, // 0=rejected channel frequency
|
||||
};
|
||||
enum {
|
||||
MCMD_PING_ANS_RFU = 0xFE,
|
||||
MCMD_PING_ANS_FQACK = 0x01
|
||||
};
|
||||
|
||||
enum {
|
||||
MCMD_DEVS_EXT_POWER = 0x00, // external power supply
|
||||
MCMD_DEVS_BATT_MIN = 0x01, // min battery value
|
||||
MCMD_DEVS_BATT_MAX = 0xFE, // max battery value
|
||||
MCMD_DEVS_BATT_NOINFO = 0xFF, // unknown battery level
|
||||
};
|
||||
|
||||
// Bit fields byte#3 of MCMD_LADR_REQ payload
|
||||
enum {
|
||||
MCMD_LADR_CHP_125ON = 0x60, // special channel page enable, bits applied to 64..71
|
||||
MCMD_LADR_CHP_125OFF = 0x70, // ditto
|
||||
MCMD_LADR_N3RFU_MASK = 0x80,
|
||||
MCMD_LADR_CHPAGE_MASK = 0xF0,
|
||||
MCMD_LADR_REPEAT_MASK = 0x0F,
|
||||
MCMD_LADR_REPEAT_1 = 0x01,
|
||||
MCMD_LADR_CHPAGE_1 = 0x10
|
||||
};
|
||||
// Bit fields byte#0 of MCMD_LADR_REQ payload
|
||||
enum {
|
||||
MCMD_LADR_DR_MASK = 0xF0,
|
||||
MCMD_LADR_POW_MASK = 0x0F,
|
||||
MCMD_LADR_DR_SHIFT = 4,
|
||||
MCMD_LADR_POW_SHIFT = 0,
|
||||
#if defined(CFG_eu868)
|
||||
MCMD_LADR_SF12 = DR_SF12<<4,
|
||||
MCMD_LADR_SF11 = DR_SF11<<4,
|
||||
MCMD_LADR_SF10 = DR_SF10<<4,
|
||||
MCMD_LADR_SF9 = DR_SF9 <<4,
|
||||
MCMD_LADR_SF8 = DR_SF8 <<4,
|
||||
MCMD_LADR_SF7 = DR_SF7 <<4,
|
||||
MCMD_LADR_SF7B = DR_SF7B<<4,
|
||||
MCMD_LADR_FSK = DR_FSK <<4,
|
||||
|
||||
MCMD_LADR_20dBm = 0,
|
||||
MCMD_LADR_14dBm = 1,
|
||||
MCMD_LADR_11dBm = 2,
|
||||
MCMD_LADR_8dBm = 3,
|
||||
MCMD_LADR_5dBm = 4,
|
||||
MCMD_LADR_2dBm = 5,
|
||||
#elif defined(CFG_us915)
|
||||
MCMD_LADR_SF10 = DR_SF10<<4,
|
||||
MCMD_LADR_SF9 = DR_SF9 <<4,
|
||||
MCMD_LADR_SF8 = DR_SF8 <<4,
|
||||
MCMD_LADR_SF7 = DR_SF7 <<4,
|
||||
MCMD_LADR_SF8C = DR_SF8C<<4,
|
||||
MCMD_LADR_SF12CR = DR_SF12CR<<4,
|
||||
MCMD_LADR_SF11CR = DR_SF11CR<<4,
|
||||
MCMD_LADR_SF10CR = DR_SF10CR<<4,
|
||||
MCMD_LADR_SF9CR = DR_SF9CR<<4,
|
||||
MCMD_LADR_SF8CR = DR_SF8CR<<4,
|
||||
MCMD_LADR_SF7CR = DR_SF7CR<<4,
|
||||
|
||||
MCMD_LADR_30dBm = 0,
|
||||
MCMD_LADR_28dBm = 1,
|
||||
MCMD_LADR_26dBm = 2,
|
||||
MCMD_LADR_24dBm = 3,
|
||||
MCMD_LADR_22dBm = 4,
|
||||
MCMD_LADR_20dBm = 5,
|
||||
MCMD_LADR_18dBm = 6,
|
||||
MCMD_LADR_16dBm = 7,
|
||||
MCMD_LADR_14dBm = 8,
|
||||
MCMD_LADR_12dBm = 9,
|
||||
MCMD_LADR_10dBm = 10
|
||||
#endif
|
||||
};
|
||||
|
||||
// Device address
|
||||
typedef u4_t devaddr_t;
|
||||
|
||||
// RX quality (device)
|
||||
enum { RSSI_OFF=64, SNR_SCALEUP=4 };
|
||||
|
||||
inline sf_t getSf (rps_t params) { return (sf_t)(params & 0x7); }
|
||||
inline rps_t setSf (rps_t params, sf_t sf) { return (rps_t)((params & ~0x7) | sf); }
|
||||
inline bw_t getBw (rps_t params) { return (bw_t)((params >> 3) & 0x3); }
|
||||
inline rps_t setBw (rps_t params, bw_t cr) { return (rps_t)((params & ~0x18) | (cr<<3)); }
|
||||
inline cr_t getCr (rps_t params) { return (cr_t)((params >> 5) & 0x3); }
|
||||
inline rps_t setCr (rps_t params, cr_t cr) { return (rps_t)((params & ~0x60) | (cr<<5)); }
|
||||
inline int getNocrc(rps_t params) { return ((params >> 7) & 0x1); }
|
||||
inline rps_t setNocrc(rps_t params, int nocrc) { return (rps_t)((params & ~0x80) | (nocrc<<7)); }
|
||||
inline int getIh (rps_t params) { return ((params >> 8) & 0xFF); }
|
||||
inline rps_t setIh (rps_t params, int ih) { return (rps_t)((params & ~0xFF00) | (ih<<8)); }
|
||||
inline rps_t makeRps (sf_t sf, bw_t bw, cr_t cr, int ih, int nocrc) {
|
||||
return sf | (bw<<3) | (cr<<5) | (nocrc?(1<<7):0) | ((ih&0xFF)<<8);
|
||||
}
|
||||
#define MAKERPS(sf,bw,cr,ih,nocrc) ((rps_t)((sf) | ((bw)<<3) | ((cr)<<5) | ((nocrc)?(1<<7):0) | ((ih&0xFF)<<8)))
|
||||
// Two frames with params r1/r2 would interfere on air: same SFx + BWx
|
||||
inline int sameSfBw(rps_t r1, rps_t r2) { return ((r1^r2)&0x1F) == 0; }
|
||||
|
||||
extern CONST_TABLE(u1_t, _DR2RPS_CRC)[];
|
||||
inline rps_t updr2rps (dr_t dr) { return (rps_t)TABLE_GET_U1(_DR2RPS_CRC, dr+1); }
|
||||
inline rps_t dndr2rps (dr_t dr) { return setNocrc(updr2rps(dr),1); }
|
||||
inline int isFasterDR (dr_t dr1, dr_t dr2) { return dr1 > dr2; }
|
||||
inline int isSlowerDR (dr_t dr1, dr_t dr2) { return dr1 < dr2; }
|
||||
inline dr_t incDR (dr_t dr) { return TABLE_GET_U1(_DR2RPS_CRC, dr+2)==ILLEGAL_RPS ? dr : (dr_t)(dr+1); } // increase data rate
|
||||
inline dr_t decDR (dr_t dr) { return TABLE_GET_U1(_DR2RPS_CRC, dr )==ILLEGAL_RPS ? dr : (dr_t)(dr-1); } // decrease data rate
|
||||
inline dr_t assertDR (dr_t dr) { return TABLE_GET_U1(_DR2RPS_CRC, dr+1)==ILLEGAL_RPS ? DR_DFLTMIN : dr; } // force into a valid DR
|
||||
inline bit_t validDR (dr_t dr) { return TABLE_GET_U1(_DR2RPS_CRC, dr+1)!=ILLEGAL_RPS; } // in range
|
||||
inline dr_t lowerDR (dr_t dr, u1_t n) { while(n--){dr=decDR(dr);} return dr; } // decrease data rate by n steps
|
||||
|
||||
//
|
||||
// BEG: Keep in sync with lorabase.hpp
|
||||
// ================================================================================
|
||||
|
||||
|
||||
// Convert between dBm values and power codes (MCMD_LADR_XdBm)
|
||||
s1_t pow2dBm (u1_t mcmd_ladr_p1);
|
||||
// Calculate airtime
|
||||
ostime_t calcAirTime (rps_t rps, u1_t plen);
|
||||
// Sensitivity at given SF/BW
|
||||
int getSensitivity (rps_t rps);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _lorabase_h_
|
129
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/oslmic.c
Normal file
129
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/oslmic.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014-2015 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Zurich Research Lab - initial API, implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "lmic.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
// RUNTIME STATE
|
||||
static struct {
|
||||
osjob_t* scheduledjobs;
|
||||
osjob_t* runnablejobs;
|
||||
} OS;
|
||||
|
||||
void os_init () {
|
||||
memset(&OS, 0x00, sizeof(OS));
|
||||
hal_init();
|
||||
radio_init();
|
||||
LMIC_init();
|
||||
}
|
||||
|
||||
ostime_t os_getTime () {
|
||||
return hal_ticks();
|
||||
}
|
||||
|
||||
static u1_t unlinkjob (osjob_t** pnext, osjob_t* job) {
|
||||
for( ; *pnext; pnext = &((*pnext)->next)) {
|
||||
if(*pnext == job) { // unlink
|
||||
*pnext = job->next;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// clear scheduled job
|
||||
void os_clearCallback (osjob_t* job) {
|
||||
hal_disableIRQs();
|
||||
u1_t res = unlinkjob(&OS.scheduledjobs, job) || unlinkjob(&OS.runnablejobs, job);
|
||||
hal_enableIRQs();
|
||||
#if LMIC_DEBUG_LEVEL > 1
|
||||
if (res)
|
||||
lmic_printf("%lu: Cleared job %p\n", os_getTime(), job);
|
||||
#endif
|
||||
}
|
||||
|
||||
// schedule immediately runnable job
|
||||
void os_setCallback (osjob_t* job, osjobcb_t cb) {
|
||||
osjob_t** pnext;
|
||||
hal_disableIRQs();
|
||||
// remove if job was already queued
|
||||
os_clearCallback(job);
|
||||
// fill-in job
|
||||
job->func = cb;
|
||||
job->next = NULL;
|
||||
// add to end of run queue
|
||||
for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next));
|
||||
*pnext = job;
|
||||
hal_enableIRQs();
|
||||
#if LMIC_DEBUG_LEVEL > 1
|
||||
lmic_printf("%lu: Scheduled job %p, cb %p ASAP\n", os_getTime(), job, cb);
|
||||
#endif
|
||||
}
|
||||
|
||||
// schedule timed job
|
||||
void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) {
|
||||
osjob_t** pnext;
|
||||
hal_disableIRQs();
|
||||
// remove if job was already queued
|
||||
os_clearCallback(job);
|
||||
// fill-in job
|
||||
job->deadline = time;
|
||||
job->func = cb;
|
||||
job->next = NULL;
|
||||
// insert into schedule
|
||||
for(pnext=&OS.scheduledjobs; *pnext; pnext=&((*pnext)->next)) {
|
||||
if((*pnext)->deadline - time > 0) { // (cmp diff, not abs!)
|
||||
// enqueue before next element and stop
|
||||
job->next = *pnext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*pnext = job;
|
||||
hal_enableIRQs();
|
||||
#if LMIC_DEBUG_LEVEL > 1
|
||||
lmic_printf("%lu: Scheduled job %p, cb %p at %lu\n", os_getTime(), job, cb, time);
|
||||
#endif
|
||||
}
|
||||
|
||||
// execute jobs from timer and from run queue
|
||||
void os_runloop () {
|
||||
while(1) {
|
||||
os_runloop_once();
|
||||
}
|
||||
}
|
||||
|
||||
void os_runloop_once() {
|
||||
#if LMIC_DEBUG_LEVEL > 1
|
||||
bool has_deadline = false;
|
||||
#endif
|
||||
osjob_t* j = NULL;
|
||||
hal_disableIRQs();
|
||||
// check for runnable jobs
|
||||
if(OS.runnablejobs) {
|
||||
j = OS.runnablejobs;
|
||||
OS.runnablejobs = j->next;
|
||||
} else if(OS.scheduledjobs && hal_checkTimer(OS.scheduledjobs->deadline)) { // check for expired timed jobs
|
||||
j = OS.scheduledjobs;
|
||||
OS.scheduledjobs = j->next;
|
||||
#if LMIC_DEBUG_LEVEL > 1
|
||||
has_deadline = true;
|
||||
#endif
|
||||
} else { // nothing pending
|
||||
hal_sleep(); // wake by irq (timer already restarted)
|
||||
}
|
||||
hal_enableIRQs();
|
||||
if(j) { // run job callback
|
||||
#if LMIC_DEBUG_LEVEL > 1
|
||||
lmic_printf("%lu: Running job %p, cb %p, deadline %lu\n", os_getTime(), j, j->func, has_deadline ? j->deadline : 0);
|
||||
#endif
|
||||
j->func(j);
|
||||
}
|
||||
}
|
288
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/oslmic.h
Normal file
288
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/oslmic.h
Normal file
@ -0,0 +1,288 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014-2015 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Zurich Research Lab - initial API, implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
//! \file
|
||||
#ifndef _oslmic_h_
|
||||
#define _oslmic_h_
|
||||
|
||||
// Dependencies required for the LoRa MAC in C to run.
|
||||
// These settings can be adapted to the underlying system.
|
||||
// You should not, however, change the lmic.[hc]
|
||||
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Target platform as C library
|
||||
typedef uint8_t bit_t;
|
||||
typedef uint8_t u1_t;
|
||||
typedef int8_t s1_t;
|
||||
typedef uint16_t u2_t;
|
||||
typedef int16_t s2_t;
|
||||
typedef uint32_t u4_t;
|
||||
typedef int32_t s4_t;
|
||||
typedef unsigned int uint;
|
||||
typedef const char* str_t;
|
||||
|
||||
#include <string.h>
|
||||
#include "hal.h"
|
||||
#define EV(a,b,c) /**/
|
||||
#define DO_DEVDB(field1,field2) /**/
|
||||
#if !defined(CFG_noassert)
|
||||
#define ASSERT(cond) if(!(cond)) hal_failed(__FILE__, __LINE__)
|
||||
#else
|
||||
#define ASSERT(cond) /**/
|
||||
#endif
|
||||
|
||||
#define os_clearMem(a,b) memset(a,0,b)
|
||||
#define os_copyMem(a,b,c) memcpy(a,b,c)
|
||||
|
||||
typedef struct osjob_t osjob_t;
|
||||
typedef struct band_t band_t;
|
||||
typedef struct chnldef_t chnldef_t;
|
||||
typedef struct rxsched_t rxsched_t;
|
||||
typedef struct bcninfo_t bcninfo_t;
|
||||
typedef const u1_t* xref2cu1_t;
|
||||
typedef u1_t* xref2u1_t;
|
||||
#define TYPEDEF_xref2rps_t typedef rps_t* xref2rps_t
|
||||
#define TYPEDEF_xref2rxsched_t typedef rxsched_t* xref2rxsched_t
|
||||
#define TYPEDEF_xref2chnldef_t typedef chnldef_t* xref2chnldef_t
|
||||
#define TYPEDEF_xref2band_t typedef band_t* xref2band_t
|
||||
#define TYPEDEF_xref2osjob_t typedef osjob_t* xref2osjob_t
|
||||
|
||||
#define SIZEOFEXPR(x) sizeof(x)
|
||||
|
||||
#define ON_LMIC_EVENT(ev) onEvent(ev)
|
||||
#define DECL_ON_LMIC_EVENT void onEvent(ev_t e)
|
||||
|
||||
extern u4_t AESAUX[];
|
||||
extern u4_t AESKEY[];
|
||||
#define AESkey ((u1_t*)AESKEY)
|
||||
#define AESaux ((u1_t*)AESAUX)
|
||||
#define FUNC_ADDR(func) (&(func))
|
||||
|
||||
u1_t radio_rand1 (void);
|
||||
#define os_getRndU1() radio_rand1()
|
||||
|
||||
#define DEFINE_LMIC struct lmic_t LMIC
|
||||
#define DECLARE_LMIC extern struct lmic_t LMIC
|
||||
|
||||
void radio_init (void);
|
||||
void radio_irq_handler (u1_t dio);
|
||||
void os_init (void);
|
||||
void os_runloop (void);
|
||||
void os_runloop_once (void);
|
||||
|
||||
//================================================================================
|
||||
|
||||
|
||||
#ifndef RX_RAMPUP
|
||||
#define RX_RAMPUP (us2osticks(2000))
|
||||
#endif
|
||||
#ifndef TX_RAMPUP
|
||||
#define TX_RAMPUP (us2osticks(2000))
|
||||
#endif
|
||||
|
||||
#ifndef OSTICKS_PER_SEC
|
||||
#define OSTICKS_PER_SEC 32768
|
||||
#elif OSTICKS_PER_SEC < 10000 || OSTICKS_PER_SEC > 64516
|
||||
#error Illegal OSTICKS_PER_SEC - must be in range [10000:64516]. One tick must be 15.5us .. 100us long.
|
||||
#endif
|
||||
|
||||
typedef s4_t ostime_t;
|
||||
|
||||
#if !HAS_ostick_conv
|
||||
#define us2osticks(us) ((ostime_t)( ((int64_t)(us) * OSTICKS_PER_SEC) / 1000000))
|
||||
#define ms2osticks(ms) ((ostime_t)( ((int64_t)(ms) * OSTICKS_PER_SEC) / 1000))
|
||||
#define sec2osticks(sec) ((ostime_t)( (int64_t)(sec) * OSTICKS_PER_SEC))
|
||||
#define osticks2ms(os) ((s4_t)(((os)*(int64_t)1000 ) / OSTICKS_PER_SEC))
|
||||
#define osticks2us(os) ((s4_t)(((os)*(int64_t)1000000 ) / OSTICKS_PER_SEC))
|
||||
// Special versions
|
||||
#define us2osticksCeil(us) ((ostime_t)( ((int64_t)(us) * OSTICKS_PER_SEC + 999999) / 1000000))
|
||||
#define us2osticksRound(us) ((ostime_t)( ((int64_t)(us) * OSTICKS_PER_SEC + 500000) / 1000000))
|
||||
#define ms2osticksCeil(ms) ((ostime_t)( ((int64_t)(ms) * OSTICKS_PER_SEC + 999) / 1000))
|
||||
#define ms2osticksRound(ms) ((ostime_t)( ((int64_t)(ms) * OSTICKS_PER_SEC + 500) / 1000))
|
||||
#endif
|
||||
|
||||
|
||||
struct osjob_t; // fwd decl.
|
||||
typedef void (*osjobcb_t) (struct osjob_t*);
|
||||
struct osjob_t {
|
||||
struct osjob_t* next;
|
||||
ostime_t deadline;
|
||||
osjobcb_t func;
|
||||
};
|
||||
TYPEDEF_xref2osjob_t;
|
||||
|
||||
|
||||
#ifndef HAS_os_calls
|
||||
|
||||
#ifndef os_getDevKey
|
||||
void os_getDevKey (xref2u1_t buf);
|
||||
#endif
|
||||
#ifndef os_getArtEui
|
||||
void os_getArtEui (xref2u1_t buf);
|
||||
#endif
|
||||
#ifndef os_getDevEui
|
||||
void os_getDevEui (xref2u1_t buf);
|
||||
#endif
|
||||
#ifndef os_setCallback
|
||||
void os_setCallback (xref2osjob_t job, osjobcb_t cb);
|
||||
#endif
|
||||
#ifndef os_setTimedCallback
|
||||
void os_setTimedCallback (xref2osjob_t job, ostime_t time, osjobcb_t cb);
|
||||
#endif
|
||||
#ifndef os_clearCallback
|
||||
void os_clearCallback (xref2osjob_t job);
|
||||
#endif
|
||||
#ifndef os_getTime
|
||||
ostime_t os_getTime (void);
|
||||
#endif
|
||||
#ifndef os_getTimeSecs
|
||||
uint os_getTimeSecs (void);
|
||||
#endif
|
||||
#ifndef os_radio
|
||||
void os_radio (u1_t mode);
|
||||
#endif
|
||||
#ifndef os_getBattLevel
|
||||
u1_t os_getBattLevel (void);
|
||||
#endif
|
||||
|
||||
#ifndef os_rlsbf4
|
||||
//! Read 32-bit quantity from given pointer in little endian byte order.
|
||||
u4_t os_rlsbf4 (xref2cu1_t buf);
|
||||
#endif
|
||||
#ifndef os_wlsbf4
|
||||
//! Write 32-bit quntity into buffer in little endian byte order.
|
||||
void os_wlsbf4 (xref2u1_t buf, u4_t value);
|
||||
#endif
|
||||
#ifndef os_rmsbf4
|
||||
//! Read 32-bit quantity from given pointer in big endian byte order.
|
||||
u4_t os_rmsbf4 (xref2cu1_t buf);
|
||||
#endif
|
||||
#ifndef os_wmsbf4
|
||||
//! Write 32-bit quntity into buffer in big endian byte order.
|
||||
void os_wmsbf4 (xref2u1_t buf, u4_t value);
|
||||
#endif
|
||||
#ifndef os_rlsbf2
|
||||
//! Read 16-bit quantity from given pointer in little endian byte order.
|
||||
u2_t os_rlsbf2 (xref2cu1_t buf);
|
||||
#endif
|
||||
#ifndef os_wlsbf2
|
||||
//! Write 16-bit quntity into buffer in little endian byte order.
|
||||
void os_wlsbf2 (xref2u1_t buf, u2_t value);
|
||||
#endif
|
||||
|
||||
//! Get random number (default impl for u2_t).
|
||||
#ifndef os_getRndU2
|
||||
#define os_getRndU2() ((u2_t)((os_getRndU1()<<8)|os_getRndU1()))
|
||||
#endif
|
||||
#ifndef os_crc16
|
||||
u2_t os_crc16 (xref2u1_t d, uint len);
|
||||
#endif
|
||||
|
||||
#endif // !HAS_os_calls
|
||||
|
||||
// ======================================================================
|
||||
// Table support
|
||||
// These macros for defining a table of constants and retrieving values
|
||||
// from it makes it easier for other platforms (like AVR) to optimize
|
||||
// table accesses.
|
||||
// Use CONST_TABLE() whenever declaring or defining a table, and
|
||||
// TABLE_GET_xx whenever accessing its values. The actual name of the
|
||||
// declared variable will be modified to prevent accidental direct
|
||||
// access. The accessor macros forward to an inline function to allow
|
||||
// proper type checking of the array element type.
|
||||
|
||||
// Helper to add a prefix to the table name
|
||||
#define RESOLVE_TABLE(table) constant_table_ ## table
|
||||
|
||||
// Accessors for table elements
|
||||
#define TABLE_GET_U1(table, index) table_get_u1(RESOLVE_TABLE(table), index)
|
||||
#define TABLE_GET_S1(table, index) table_get_s1(RESOLVE_TABLE(table), index)
|
||||
#define TABLE_GET_U2(table, index) table_get_u2(RESOLVE_TABLE(table), index)
|
||||
#define TABLE_GET_S2(table, index) table_get_s2(RESOLVE_TABLE(table), index)
|
||||
#define TABLE_GET_U4(table, index) table_get_u4(RESOLVE_TABLE(table), index)
|
||||
#define TABLE_GET_S4(table, index) table_get_s4(RESOLVE_TABLE(table), index)
|
||||
#define TABLE_GET_OSTIME(table, index) table_get_ostime(RESOLVE_TABLE(table), index)
|
||||
#define TABLE_GET_U1_TWODIM(table, index1, index2) table_get_u1(RESOLVE_TABLE(table)[index1], index2)
|
||||
|
||||
#if defined(__AVR__)
|
||||
#include <avr/pgmspace.h>
|
||||
// Macro to define the getter functions. This loads data from
|
||||
// progmem using pgm_read_xx, or accesses memory directly when the
|
||||
// index is a constant so gcc can optimize it away;
|
||||
#define TABLE_GETTER(postfix, type, pgm_type) \
|
||||
inline type table_get ## postfix(const type *table, size_t index) { \
|
||||
if (__builtin_constant_p(table[index])) \
|
||||
return table[index]; \
|
||||
return pgm_read_ ## pgm_type(&table[index]); \
|
||||
}
|
||||
|
||||
TABLE_GETTER(_u1, u1_t, byte);
|
||||
TABLE_GETTER(_s1, s1_t, byte);
|
||||
TABLE_GETTER(_u2, u2_t, word);
|
||||
TABLE_GETTER(_s2, s2_t, word);
|
||||
TABLE_GETTER(_u4, u4_t, dword);
|
||||
TABLE_GETTER(_s4, s4_t, dword);
|
||||
|
||||
// This assumes ostime_t is 4 bytes, so error out if it is not
|
||||
typedef int check_sizeof_ostime_t[(sizeof(ostime_t) == 4) ? 0 : -1];
|
||||
TABLE_GETTER(_ostime, ostime_t, dword);
|
||||
|
||||
// For AVR, store constants in PROGMEM, saving on RAM usage
|
||||
#define CONST_TABLE(type, name) const type PROGMEM RESOLVE_TABLE(name)
|
||||
|
||||
#define lmic_printf(fmt, ...) printf_P(PSTR(fmt), ## __VA_ARGS__)
|
||||
#else
|
||||
inline u1_t table_get_u1(const u1_t *table, size_t index) { return table[index]; }
|
||||
inline s1_t table_get_s1(const s1_t *table, size_t index) { return table[index]; }
|
||||
inline u2_t table_get_u2(const u2_t *table, size_t index) { return table[index]; }
|
||||
inline s2_t table_get_s2(const s2_t *table, size_t index) { return table[index]; }
|
||||
inline u4_t table_get_u4(const u4_t *table, size_t index) { return table[index]; }
|
||||
inline s4_t table_get_s4(const s4_t *table, size_t index) { return table[index]; }
|
||||
inline ostime_t table_get_ostime(const ostime_t *table, size_t index) { return table[index]; }
|
||||
|
||||
// Declare a table
|
||||
#define CONST_TABLE(type, name) const type RESOLVE_TABLE(name)
|
||||
#define lmic_printf printf
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
// AES support
|
||||
// !!Keep in sync with lorabase.hpp!!
|
||||
|
||||
#ifndef AES_ENC // if AES_ENC is defined as macro all other values must be too
|
||||
#define AES_ENC 0x00
|
||||
#define AES_DEC 0x01
|
||||
#define AES_MIC 0x02
|
||||
#define AES_CTR 0x04
|
||||
#define AES_MICNOAUX 0x08
|
||||
#endif
|
||||
#ifndef AESkey // if AESkey is defined as macro all other values must be too
|
||||
extern xref2u1_t AESkey;
|
||||
extern xref2u1_t AESaux;
|
||||
#endif
|
||||
#ifndef os_aes
|
||||
u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _oslmic_h_
|
856
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c
Normal file
856
lib/arduino-lmic-1.5.0-arduino-2-tweaked/src/lmic/radio.c
Normal file
@ -0,0 +1,856 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014-2015 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Zurich Research Lab - initial API, implementation and documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "lmic.h"
|
||||
|
||||
// ----------------------------------------
|
||||
// Registers Mapping
|
||||
#define RegFifo 0x00 // common
|
||||
#define RegOpMode 0x01 // common
|
||||
#define FSKRegBitrateMsb 0x02
|
||||
#define FSKRegBitrateLsb 0x03
|
||||
#define FSKRegFdevMsb 0x04
|
||||
#define FSKRegFdevLsb 0x05
|
||||
#define RegFrfMsb 0x06 // common
|
||||
#define RegFrfMid 0x07 // common
|
||||
#define RegFrfLsb 0x08 // common
|
||||
#define RegPaConfig 0x09 // common
|
||||
#define RegPaRamp 0x0A // common
|
||||
#define RegOcp 0x0B // common
|
||||
#define RegLna 0x0C // common
|
||||
#define FSKRegRxConfig 0x0D
|
||||
#define LORARegFifoAddrPtr 0x0D
|
||||
#define FSKRegRssiConfig 0x0E
|
||||
#define LORARegFifoTxBaseAddr 0x0E
|
||||
#define FSKRegRssiCollision 0x0F
|
||||
#define LORARegFifoRxBaseAddr 0x0F
|
||||
#define FSKRegRssiThresh 0x10
|
||||
#define LORARegFifoRxCurrentAddr 0x10
|
||||
#define FSKRegRssiValue 0x11
|
||||
#define LORARegIrqFlagsMask 0x11
|
||||
#define FSKRegRxBw 0x12
|
||||
#define LORARegIrqFlags 0x12
|
||||
#define FSKRegAfcBw 0x13
|
||||
#define LORARegRxNbBytes 0x13
|
||||
#define FSKRegOokPeak 0x14
|
||||
#define LORARegRxHeaderCntValueMsb 0x14
|
||||
#define FSKRegOokFix 0x15
|
||||
#define LORARegRxHeaderCntValueLsb 0x15
|
||||
#define FSKRegOokAvg 0x16
|
||||
#define LORARegRxPacketCntValueMsb 0x16
|
||||
#define LORARegRxpacketCntValueLsb 0x17
|
||||
#define LORARegModemStat 0x18
|
||||
#define LORARegPktSnrValue 0x19
|
||||
#define FSKRegAfcFei 0x1A
|
||||
#define LORARegPktRssiValue 0x1A
|
||||
#define FSKRegAfcMsb 0x1B
|
||||
#define LORARegRssiValue 0x1B
|
||||
#define FSKRegAfcLsb 0x1C
|
||||
#define LORARegHopChannel 0x1C
|
||||
#define FSKRegFeiMsb 0x1D
|
||||
#define LORARegModemConfig1 0x1D
|
||||
#define FSKRegFeiLsb 0x1E
|
||||
#define LORARegModemConfig2 0x1E
|
||||
#define FSKRegPreambleDetect 0x1F
|
||||
#define LORARegSymbTimeoutLsb 0x1F
|
||||
#define FSKRegRxTimeout1 0x20
|
||||
#define LORARegPreambleMsb 0x20
|
||||
#define FSKRegRxTimeout2 0x21
|
||||
#define LORARegPreambleLsb 0x21
|
||||
#define FSKRegRxTimeout3 0x22
|
||||
#define LORARegPayloadLength 0x22
|
||||
#define FSKRegRxDelay 0x23
|
||||
#define LORARegPayloadMaxLength 0x23
|
||||
#define FSKRegOsc 0x24
|
||||
#define LORARegHopPeriod 0x24
|
||||
#define FSKRegPreambleMsb 0x25
|
||||
#define LORARegFifoRxByteAddr 0x25
|
||||
#define LORARegModemConfig3 0x26
|
||||
#define FSKRegPreambleLsb 0x26
|
||||
#define FSKRegSyncConfig 0x27
|
||||
#define LORARegFeiMsb 0x28
|
||||
#define FSKRegSyncValue1 0x28
|
||||
#define LORAFeiMib 0x29
|
||||
#define FSKRegSyncValue2 0x29
|
||||
#define LORARegFeiLsb 0x2A
|
||||
#define FSKRegSyncValue3 0x2A
|
||||
#define FSKRegSyncValue4 0x2B
|
||||
#define LORARegRssiWideband 0x2C
|
||||
#define FSKRegSyncValue5 0x2C
|
||||
#define FSKRegSyncValue6 0x2D
|
||||
#define FSKRegSyncValue7 0x2E
|
||||
#define FSKRegSyncValue8 0x2F
|
||||
#define FSKRegPacketConfig1 0x30
|
||||
#define FSKRegPacketConfig2 0x31
|
||||
#define LORARegDetectOptimize 0x31
|
||||
#define FSKRegPayloadLength 0x32
|
||||
#define FSKRegNodeAdrs 0x33
|
||||
#define LORARegInvertIQ 0x33
|
||||
#define FSKRegBroadcastAdrs 0x34
|
||||
#define FSKRegFifoThresh 0x35
|
||||
#define FSKRegSeqConfig1 0x36
|
||||
#define FSKRegSeqConfig2 0x37
|
||||
#define LORARegDetectionThreshold 0x37
|
||||
#define FSKRegTimerResol 0x38
|
||||
#define FSKRegTimer1Coef 0x39
|
||||
#define LORARegSyncWord 0x39
|
||||
#define FSKRegTimer2Coef 0x3A
|
||||
#define FSKRegImageCal 0x3B
|
||||
#define FSKRegTemp 0x3C
|
||||
#define FSKRegLowBat 0x3D
|
||||
#define FSKRegIrqFlags1 0x3E
|
||||
#define FSKRegIrqFlags2 0x3F
|
||||
#define RegDioMapping1 0x40 // common
|
||||
#define RegDioMapping2 0x41 // common
|
||||
#define RegVersion 0x42 // common
|
||||
// #define RegAgcRef 0x43 // common
|
||||
// #define RegAgcThresh1 0x44 // common
|
||||
// #define RegAgcThresh2 0x45 // common
|
||||
// #define RegAgcThresh3 0x46 // common
|
||||
// #define RegPllHop 0x4B // common
|
||||
// #define RegTcxo 0x58 // common
|
||||
#ifdef CFG_sx1276_radio
|
||||
#define RegPaDac 0x4D // common
|
||||
#else
|
||||
#define RegPaDac 0x5A // common
|
||||
#endif
|
||||
// #define RegPll 0x5C // common
|
||||
// #define RegPllLowPn 0x5E // common
|
||||
// #define RegFormerTemp 0x6C // common
|
||||
// #define RegBitRateFrac 0x70 // common
|
||||
|
||||
// ----------------------------------------
|
||||
// spread factors and mode for RegModemConfig2
|
||||
#define SX1272_MC2_FSK 0x00
|
||||
#define SX1272_MC2_SF7 0x70
|
||||
#define SX1272_MC2_SF8 0x80
|
||||
#define SX1272_MC2_SF9 0x90
|
||||
#define SX1272_MC2_SF10 0xA0
|
||||
#define SX1272_MC2_SF11 0xB0
|
||||
#define SX1272_MC2_SF12 0xC0
|
||||
// bandwidth for RegModemConfig1
|
||||
#define SX1272_MC1_BW_125 0x00
|
||||
#define SX1272_MC1_BW_250 0x40
|
||||
#define SX1272_MC1_BW_500 0x80
|
||||
// coding rate for RegModemConfig1
|
||||
#define SX1272_MC1_CR_4_5 0x08
|
||||
#define SX1272_MC1_CR_4_6 0x10
|
||||
#define SX1272_MC1_CR_4_7 0x18
|
||||
#define SX1272_MC1_CR_4_8 0x20
|
||||
#define SX1272_MC1_IMPLICIT_HEADER_MODE_ON 0x04 // required for receive
|
||||
#define SX1272_MC1_RX_PAYLOAD_CRCON 0x02
|
||||
#define SX1272_MC1_LOW_DATA_RATE_OPTIMIZE 0x01 // mandated for SF11 and SF12
|
||||
// transmit power configuration for RegPaConfig
|
||||
#define SX1272_PAC_PA_SELECT_PA_BOOST 0x80
|
||||
#define SX1272_PAC_PA_SELECT_RFIO_PIN 0x00
|
||||
|
||||
|
||||
// sx1276 RegModemConfig1
|
||||
#define SX1276_MC1_BW_125 0x70
|
||||
#define SX1276_MC1_BW_250 0x80
|
||||
#define SX1276_MC1_BW_500 0x90
|
||||
#define SX1276_MC1_CR_4_5 0x02
|
||||
#define SX1276_MC1_CR_4_6 0x04
|
||||
#define SX1276_MC1_CR_4_7 0x06
|
||||
#define SX1276_MC1_CR_4_8 0x08
|
||||
|
||||
#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
|
||||
|
||||
// sx1276 RegModemConfig2
|
||||
#define SX1276_MC2_RX_PAYLOAD_CRCON 0x04
|
||||
|
||||
// sx1276 RegModemConfig3
|
||||
#define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE 0x08
|
||||
#define SX1276_MC3_AGCAUTO 0x04
|
||||
|
||||
// preamble for lora networks (nibbles swapped)
|
||||
#define LORA_MAC_PREAMBLE 0x34
|
||||
|
||||
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1 0x0A
|
||||
#ifdef CFG_sx1276_radio
|
||||
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x70
|
||||
#elif CFG_sx1272_radio
|
||||
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------
|
||||
// Constants for radio registers
|
||||
#define OPMODE_LORA 0x80
|
||||
#define OPMODE_MASK 0x07
|
||||
#define OPMODE_SLEEP 0x00
|
||||
#define OPMODE_STANDBY 0x01
|
||||
#define OPMODE_FSTX 0x02
|
||||
#define OPMODE_TX 0x03
|
||||
#define OPMODE_FSRX 0x04
|
||||
#define OPMODE_RX 0x05
|
||||
#define OPMODE_RX_SINGLE 0x06
|
||||
#define OPMODE_CAD 0x07
|
||||
|
||||
// ----------------------------------------
|
||||
// Bits masking the corresponding IRQs from the radio
|
||||
#define IRQ_LORA_RXTOUT_MASK 0x80
|
||||
#define IRQ_LORA_RXDONE_MASK 0x40
|
||||
#define IRQ_LORA_CRCERR_MASK 0x20
|
||||
#define IRQ_LORA_HEADER_MASK 0x10
|
||||
#define IRQ_LORA_TXDONE_MASK 0x08
|
||||
#define IRQ_LORA_CDDONE_MASK 0x04
|
||||
#define IRQ_LORA_FHSSCH_MASK 0x02
|
||||
#define IRQ_LORA_CDDETD_MASK 0x01
|
||||
|
||||
#define IRQ_FSK1_MODEREADY_MASK 0x80
|
||||
#define IRQ_FSK1_RXREADY_MASK 0x40
|
||||
#define IRQ_FSK1_TXREADY_MASK 0x20
|
||||
#define IRQ_FSK1_PLLLOCK_MASK 0x10
|
||||
#define IRQ_FSK1_RSSI_MASK 0x08
|
||||
#define IRQ_FSK1_TIMEOUT_MASK 0x04
|
||||
#define IRQ_FSK1_PREAMBLEDETECT_MASK 0x02
|
||||
#define IRQ_FSK1_SYNCADDRESSMATCH_MASK 0x01
|
||||
#define IRQ_FSK2_FIFOFULL_MASK 0x80
|
||||
#define IRQ_FSK2_FIFOEMPTY_MASK 0x40
|
||||
#define IRQ_FSK2_FIFOLEVEL_MASK 0x20
|
||||
#define IRQ_FSK2_FIFOOVERRUN_MASK 0x10
|
||||
#define IRQ_FSK2_PACKETSENT_MASK 0x08
|
||||
#define IRQ_FSK2_PAYLOADREADY_MASK 0x04
|
||||
#define IRQ_FSK2_CRCOK_MASK 0x02
|
||||
#define IRQ_FSK2_LOWBAT_MASK 0x01
|
||||
|
||||
// ----------------------------------------
|
||||
// DIO function mappings D0D1D2D3
|
||||
#define MAP_DIO0_LORA_RXDONE 0x00 // 00------
|
||||
#define MAP_DIO0_LORA_TXDONE 0x40 // 01------
|
||||
#define MAP_DIO1_LORA_RXTOUT 0x00 // --00----
|
||||
#define MAP_DIO1_LORA_NOP 0x30 // --11----
|
||||
#define MAP_DIO2_LORA_NOP 0xC0 // ----11--
|
||||
|
||||
#define MAP_DIO0_FSK_READY 0x00 // 00------ (packet sent / payload ready)
|
||||
#define MAP_DIO1_FSK_NOP 0x30 // --11----
|
||||
#define MAP_DIO2_FSK_TXNOP 0x04 // ----01--
|
||||
#define MAP_DIO2_FSK_TIMEOUT 0x08 // ----10--
|
||||
|
||||
|
||||
// FSK IMAGECAL defines
|
||||
#define RF_IMAGECAL_AUTOIMAGECAL_MASK 0x7F
|
||||
#define RF_IMAGECAL_AUTOIMAGECAL_ON 0x80
|
||||
#define RF_IMAGECAL_AUTOIMAGECAL_OFF 0x00 // Default
|
||||
|
||||
#define RF_IMAGECAL_IMAGECAL_MASK 0xBF
|
||||
#define RF_IMAGECAL_IMAGECAL_START 0x40
|
||||
|
||||
#define RF_IMAGECAL_IMAGECAL_RUNNING 0x20
|
||||
#define RF_IMAGECAL_IMAGECAL_DONE 0x00 // Default
|
||||
|
||||
|
||||
// RADIO STATE
|
||||
// (initialized by radio_init(), used by radio_rand1())
|
||||
static u1_t randbuf[16];
|
||||
|
||||
|
||||
#ifdef CFG_sx1276_radio
|
||||
#define LNA_RX_GAIN (0x20|0x1)
|
||||
#elif CFG_sx1272_radio
|
||||
#define LNA_RX_GAIN (0x20|0x03)
|
||||
#else
|
||||
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
|
||||
#endif
|
||||
|
||||
|
||||
static void writeReg (u1_t addr, u1_t data ) {
|
||||
hal_pin_nss(0);
|
||||
hal_spi(addr | 0x80);
|
||||
hal_spi(data);
|
||||
hal_pin_nss(1);
|
||||
}
|
||||
|
||||
static u1_t readReg (u1_t addr) {
|
||||
hal_pin_nss(0);
|
||||
hal_spi(addr & 0x7F);
|
||||
u1_t val = hal_spi(0x00);
|
||||
hal_pin_nss(1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) {
|
||||
hal_pin_nss(0);
|
||||
hal_spi(addr | 0x80);
|
||||
for (u1_t i=0; i<len; i++) {
|
||||
hal_spi(buf[i]);
|
||||
}
|
||||
hal_pin_nss(1);
|
||||
}
|
||||
|
||||
static void readBuf (u1_t addr, xref2u1_t buf, u1_t len) {
|
||||
hal_pin_nss(0);
|
||||
hal_spi(addr & 0x7F);
|
||||
for (u1_t i=0; i<len; i++) {
|
||||
buf[i] = hal_spi(0x00);
|
||||
}
|
||||
hal_pin_nss(1);
|
||||
}
|
||||
|
||||
static void opmode (u1_t mode) {
|
||||
writeReg(RegOpMode, (readReg(RegOpMode) & ~OPMODE_MASK) | mode);
|
||||
}
|
||||
|
||||
static void opmodeLora() {
|
||||
u1_t u = OPMODE_LORA;
|
||||
#ifdef CFG_sx1276_radio
|
||||
u |= 0x8; // TBD: sx1276 high freq
|
||||
#endif
|
||||
writeReg(RegOpMode, u);
|
||||
}
|
||||
|
||||
static void opmodeFSK() {
|
||||
u1_t u = 0;
|
||||
#ifdef CFG_sx1276_radio
|
||||
u |= 0x8; // TBD: sx1276 high freq
|
||||
#endif
|
||||
writeReg(RegOpMode, u);
|
||||
}
|
||||
|
||||
// configure LoRa modem (cfg1, cfg2)
|
||||
static void configLoraModem () {
|
||||
sf_t sf = getSf(LMIC.rps);
|
||||
|
||||
#ifdef CFG_sx1276_radio
|
||||
u1_t mc1 = 0, mc2 = 0, mc3 = 0;
|
||||
|
||||
switch (getBw(LMIC.rps)) {
|
||||
case BW125: mc1 |= SX1276_MC1_BW_125; break;
|
||||
case BW250: mc1 |= SX1276_MC1_BW_250; break;
|
||||
case BW500: mc1 |= SX1276_MC1_BW_500; break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
switch( getCr(LMIC.rps) ) {
|
||||
case CR_4_5: mc1 |= SX1276_MC1_CR_4_5; break;
|
||||
case CR_4_6: mc1 |= SX1276_MC1_CR_4_6; break;
|
||||
case CR_4_7: mc1 |= SX1276_MC1_CR_4_7; break;
|
||||
case CR_4_8: mc1 |= SX1276_MC1_CR_4_8; break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
if (getIh(LMIC.rps)) {
|
||||
mc1 |= SX1276_MC1_IMPLICIT_HEADER_MODE_ON;
|
||||
writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
|
||||
}
|
||||
// set ModemConfig1
|
||||
writeReg(LORARegModemConfig1, mc1);
|
||||
|
||||
mc2 = (SX1272_MC2_SF7 + ((sf-1)<<4));
|
||||
if (getNocrc(LMIC.rps) == 0) {
|
||||
mc2 |= SX1276_MC2_RX_PAYLOAD_CRCON;
|
||||
}
|
||||
writeReg(LORARegModemConfig2, mc2);
|
||||
|
||||
mc3 = SX1276_MC3_AGCAUTO;
|
||||
if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) {
|
||||
mc3 |= SX1276_MC3_LOW_DATA_RATE_OPTIMIZE;
|
||||
}
|
||||
writeReg(LORARegModemConfig3, mc3);
|
||||
#elif CFG_sx1272_radio
|
||||
u1_t mc1 = (getBw(LMIC.rps)<<6);
|
||||
|
||||
switch( getCr(LMIC.rps) ) {
|
||||
case CR_4_5: mc1 |= SX1272_MC1_CR_4_5; break;
|
||||
case CR_4_6: mc1 |= SX1272_MC1_CR_4_6; break;
|
||||
case CR_4_7: mc1 |= SX1272_MC1_CR_4_7; break;
|
||||
case CR_4_8: mc1 |= SX1272_MC1_CR_4_8; break;
|
||||
}
|
||||
|
||||
if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) {
|
||||
mc1 |= SX1272_MC1_LOW_DATA_RATE_OPTIMIZE;
|
||||
}
|
||||
|
||||
if (getNocrc(LMIC.rps) == 0) {
|
||||
mc1 |= SX1272_MC1_RX_PAYLOAD_CRCON;
|
||||
}
|
||||
|
||||
if (getIh(LMIC.rps)) {
|
||||
mc1 |= SX1272_MC1_IMPLICIT_HEADER_MODE_ON;
|
||||
writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
|
||||
}
|
||||
// set ModemConfig1
|
||||
writeReg(LORARegModemConfig1, mc1);
|
||||
|
||||
// set ModemConfig2 (sf, AgcAutoOn=1 SymbTimeoutHi=00)
|
||||
writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x04);
|
||||
#else
|
||||
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
|
||||
#endif /* CFG_sx1272_radio */
|
||||
}
|
||||
|
||||
static void configChannel () {
|
||||
// set frequency: FQ = (FRF * 32 Mhz) / (2 ^ 19)
|
||||
uint64_t frf = ((uint64_t)LMIC.freq << 19) / 32000000;
|
||||
writeReg(RegFrfMsb, (u1_t)(frf>>16));
|
||||
writeReg(RegFrfMid, (u1_t)(frf>> 8));
|
||||
writeReg(RegFrfLsb, (u1_t)(frf>> 0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void configPower () {
|
||||
#ifdef CFG_sx1276_radio
|
||||
// no boost used for now
|
||||
s1_t pw = (s1_t)LMIC.txpow;
|
||||
if(pw > 15) {
|
||||
pw = 15;
|
||||
} else if(pw < 2) {
|
||||
pw = 2;
|
||||
}
|
||||
// check board type for BOOST pin
|
||||
writeReg(RegPaConfig, (u1_t)(0x80|(pw&0xf))); // sets PA_BOOST pin (original lmic)
|
||||
//writeReg(RegPaConfig, (u1_t)(pw&0xf)); // sets RFO pin (patched lmic)
|
||||
writeReg(RegPaDac, readReg(RegPaDac)|0x4);
|
||||
|
||||
#elif CFG_sx1272_radio
|
||||
// set PA config (2-17 dBm using PA_BOOST)
|
||||
s1_t pw = (s1_t)LMIC.txpow;
|
||||
if(pw > 17) {
|
||||
pw = 17;
|
||||
} else if(pw < 2) {
|
||||
pw = 2;
|
||||
}
|
||||
writeReg(RegPaConfig, (u1_t)(0x80|(pw-2)));
|
||||
#else
|
||||
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
|
||||
#endif /* CFG_sx1272_radio */
|
||||
}
|
||||
|
||||
static void txfsk () {
|
||||
// select FSK modem (from sleep mode)
|
||||
writeReg(RegOpMode, 0x10); // FSK, BT=0.5
|
||||
ASSERT(readReg(RegOpMode) == 0x10);
|
||||
// enter standby mode (required for FIFO loading))
|
||||
opmode(OPMODE_STANDBY);
|
||||
// set bitrate
|
||||
writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
|
||||
writeReg(FSKRegBitrateLsb, 0x80);
|
||||
// set frequency deviation
|
||||
writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
|
||||
writeReg(FSKRegFdevLsb, 0x99);
|
||||
// frame and packet handler settings
|
||||
writeReg(FSKRegPreambleMsb, 0x00);
|
||||
writeReg(FSKRegPreambleLsb, 0x05);
|
||||
writeReg(FSKRegSyncConfig, 0x12);
|
||||
writeReg(FSKRegPacketConfig1, 0xD0);
|
||||
writeReg(FSKRegPacketConfig2, 0x40);
|
||||
writeReg(FSKRegSyncValue1, 0xC1);
|
||||
writeReg(FSKRegSyncValue2, 0x94);
|
||||
writeReg(FSKRegSyncValue3, 0xC1);
|
||||
// configure frequency
|
||||
configChannel();
|
||||
// configure output power
|
||||
configPower();
|
||||
|
||||
// set the IRQ mapping DIO0=PacketSent DIO1=NOP DIO2=NOP
|
||||
writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TXNOP);
|
||||
|
||||
// initialize the payload size and address pointers
|
||||
writeReg(FSKRegPayloadLength, LMIC.dataLen+1); // (insert length byte into payload))
|
||||
|
||||
// download length byte and buffer to the radio FIFO
|
||||
writeReg(RegFifo, LMIC.dataLen);
|
||||
writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
|
||||
|
||||
// enable antenna switch for TX
|
||||
hal_pin_rxtx(1);
|
||||
|
||||
// now we actually start the transmission
|
||||
opmode(OPMODE_TX);
|
||||
}
|
||||
|
||||
static void txlora () {
|
||||
// select LoRa modem (from sleep mode)
|
||||
//writeReg(RegOpMode, OPMODE_LORA);
|
||||
opmodeLora();
|
||||
ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
|
||||
|
||||
// enter standby mode (required for FIFO loading))
|
||||
opmode(OPMODE_STANDBY);
|
||||
// configure LoRa modem (cfg1, cfg2)
|
||||
configLoraModem();
|
||||
// configure frequency
|
||||
configChannel();
|
||||
// configure output power
|
||||
writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec
|
||||
configPower();
|
||||
// set sync word
|
||||
writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
|
||||
|
||||
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
|
||||
writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP);
|
||||
// clear all radio IRQ flags
|
||||
writeReg(LORARegIrqFlags, 0xFF);
|
||||
// mask all IRQs but TxDone
|
||||
writeReg(LORARegIrqFlagsMask, ~IRQ_LORA_TXDONE_MASK);
|
||||
|
||||
// initialize the payload size and address pointers
|
||||
writeReg(LORARegFifoTxBaseAddr, 0x00);
|
||||
writeReg(LORARegFifoAddrPtr, 0x00);
|
||||
writeReg(LORARegPayloadLength, LMIC.dataLen);
|
||||
|
||||
// download buffer to the radio FIFO
|
||||
writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
|
||||
|
||||
// enable antenna switch for TX
|
||||
hal_pin_rxtx(1);
|
||||
|
||||
// now we actually start the transmission
|
||||
opmode(OPMODE_TX);
|
||||
|
||||
#if LMIC_DEBUG_LEVEL > 0
|
||||
u1_t sf = getSf(LMIC.rps) + 6; // 1 == SF7
|
||||
u1_t bw = getBw(LMIC.rps);
|
||||
u1_t cr = getCr(LMIC.rps);
|
||||
lmic_printf("%lu: TXMODE, freq=%lu, len=%d, SF=%d, BW=%d, CR=4/%d, IH=%d\n",
|
||||
os_getTime(), LMIC.freq, LMIC.dataLen, sf,
|
||||
bw == BW125 ? 125 : (bw == BW250 ? 250 : 500),
|
||||
cr == CR_4_5 ? 5 : (cr == CR_4_6 ? 6 : (cr == CR_4_7 ? 7 : 8)),
|
||||
getIh(LMIC.rps)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
// start transmitter (buf=LMIC.frame, len=LMIC.dataLen)
|
||||
static void starttx () {
|
||||
ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
|
||||
if(getSf(LMIC.rps) == FSK) { // FSK modem
|
||||
txfsk();
|
||||
} else { // LoRa modem
|
||||
txlora();
|
||||
}
|
||||
// the radio will go back to STANDBY mode as soon as the TX is finished
|
||||
// the corresponding IRQ will inform us about completion.
|
||||
}
|
||||
|
||||
enum { RXMODE_SINGLE, RXMODE_SCAN, RXMODE_RSSI };
|
||||
|
||||
static CONST_TABLE(u1_t, rxlorairqmask)[] = {
|
||||
[RXMODE_SINGLE] = IRQ_LORA_RXDONE_MASK|IRQ_LORA_RXTOUT_MASK,
|
||||
[RXMODE_SCAN] = IRQ_LORA_RXDONE_MASK,
|
||||
[RXMODE_RSSI] = 0x00,
|
||||
};
|
||||
|
||||
// start LoRa receiver (time=LMIC.rxtime, timeout=LMIC.rxsyms, result=LMIC.frame[LMIC.dataLen])
|
||||
static void rxlora (u1_t rxmode) {
|
||||
// select LoRa modem (from sleep mode)
|
||||
opmodeLora();
|
||||
ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
|
||||
// enter standby mode (warm up))
|
||||
opmode(OPMODE_STANDBY);
|
||||
// don't use MAC settings at startup
|
||||
if(rxmode == RXMODE_RSSI) { // use fixed settings for rssi scan
|
||||
writeReg(LORARegModemConfig1, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1);
|
||||
writeReg(LORARegModemConfig2, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2);
|
||||
} else { // single or continuous rx mode
|
||||
// configure LoRa modem (cfg1, cfg2)
|
||||
configLoraModem();
|
||||
// configure frequency
|
||||
configChannel();
|
||||
}
|
||||
// set LNA gain
|
||||
writeReg(RegLna, LNA_RX_GAIN);
|
||||
// set max payload size
|
||||
writeReg(LORARegPayloadMaxLength, 64);
|
||||
#if !defined(DISABLE_INVERT_IQ_ON_RX)
|
||||
// use inverted I/Q signal (prevent mote-to-mote communication)
|
||||
writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ)|(1<<6));
|
||||
#endif
|
||||
// set symbol timeout (for single rx)
|
||||
writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms);
|
||||
// set sync word
|
||||
writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
|
||||
|
||||
// configure DIO mapping DIO0=RxDone DIO1=RxTout DIO2=NOP
|
||||
writeReg(RegDioMapping1, MAP_DIO0_LORA_RXDONE|MAP_DIO1_LORA_RXTOUT|MAP_DIO2_LORA_NOP);
|
||||
// clear all radio IRQ flags
|
||||
writeReg(LORARegIrqFlags, 0xFF);
|
||||
// enable required radio IRQs
|
||||
writeReg(LORARegIrqFlagsMask, ~TABLE_GET_U1(rxlorairqmask, rxmode));
|
||||
|
||||
// enable antenna switch for RX
|
||||
hal_pin_rxtx(0);
|
||||
|
||||
// now instruct the radio to receive
|
||||
if (rxmode == RXMODE_SINGLE) { // single rx
|
||||
hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
|
||||
opmode(OPMODE_RX_SINGLE);
|
||||
} else { // continous rx (scan or rssi)
|
||||
opmode(OPMODE_RX);
|
||||
}
|
||||
|
||||
#if LMIC_DEBUG_LEVEL > 0
|
||||
if (rxmode == RXMODE_RSSI) {
|
||||
lmic_printf("RXMODE_RSSI\n");
|
||||
} else {
|
||||
u1_t sf = getSf(LMIC.rps) + 6; // 1 == SF7
|
||||
u1_t bw = getBw(LMIC.rps);
|
||||
u1_t cr = getCr(LMIC.rps);
|
||||
lmic_printf("%lu: %s, freq=%lu, SF=%d, BW=%d, CR=4/%d, IH=%d\n",
|
||||
os_getTime(),
|
||||
rxmode == RXMODE_SINGLE ? "RXMODE_SINGLE" : (rxmode == RXMODE_SCAN ? "RXMODE_SCAN" : "UNKNOWN_RX"),
|
||||
LMIC.freq, sf,
|
||||
bw == BW125 ? 125 : (bw == BW250 ? 250 : 500),
|
||||
cr == CR_4_5 ? 5 : (cr == CR_4_6 ? 6 : (cr == CR_4_7 ? 7 : 8)),
|
||||
getIh(LMIC.rps)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void rxfsk (u1_t rxmode) {
|
||||
// only single rx (no continuous scanning, no noise sampling)
|
||||
ASSERT( rxmode == RXMODE_SINGLE );
|
||||
// select FSK modem (from sleep mode)
|
||||
//writeReg(RegOpMode, 0x00); // (not LoRa)
|
||||
opmodeFSK();
|
||||
ASSERT((readReg(RegOpMode) & OPMODE_LORA) == 0);
|
||||
// enter standby mode (warm up))
|
||||
opmode(OPMODE_STANDBY);
|
||||
// configure frequency
|
||||
configChannel();
|
||||
// set LNA gain
|
||||
//writeReg(RegLna, 0x20|0x03); // max gain, boost enable
|
||||
writeReg(RegLna, LNA_RX_GAIN);
|
||||
// configure receiver
|
||||
writeReg(FSKRegRxConfig, 0x1E); // AFC auto, AGC, trigger on preamble?!?
|
||||
// set receiver bandwidth
|
||||
writeReg(FSKRegRxBw, 0x0B); // 50kHz SSb
|
||||
// set AFC bandwidth
|
||||
writeReg(FSKRegAfcBw, 0x12); // 83.3kHz SSB
|
||||
// set preamble detection
|
||||
writeReg(FSKRegPreambleDetect, 0xAA); // enable, 2 bytes, 10 chip errors
|
||||
// set sync config
|
||||
writeReg(FSKRegSyncConfig, 0x12); // no auto restart, preamble 0xAA, enable, fill FIFO, 3 bytes sync
|
||||
// set packet config
|
||||
writeReg(FSKRegPacketConfig1, 0xD8); // var-length, whitening, crc, no auto-clear, no adr filter
|
||||
writeReg(FSKRegPacketConfig2, 0x40); // packet mode
|
||||
// set sync value
|
||||
writeReg(FSKRegSyncValue1, 0xC1);
|
||||
writeReg(FSKRegSyncValue2, 0x94);
|
||||
writeReg(FSKRegSyncValue3, 0xC1);
|
||||
// set preamble timeout
|
||||
writeReg(FSKRegRxTimeout2, 0xFF);//(LMIC.rxsyms+1)/2);
|
||||
// set bitrate
|
||||
writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
|
||||
writeReg(FSKRegBitrateLsb, 0x80);
|
||||
// set frequency deviation
|
||||
writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
|
||||
writeReg(FSKRegFdevLsb, 0x99);
|
||||
|
||||
// configure DIO mapping DIO0=PayloadReady DIO1=NOP DIO2=TimeOut
|
||||
writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TIMEOUT);
|
||||
|
||||
// enable antenna switch for RX
|
||||
hal_pin_rxtx(0);
|
||||
|
||||
// now instruct the radio to receive
|
||||
hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
|
||||
opmode(OPMODE_RX); // no single rx mode available in FSK
|
||||
}
|
||||
|
||||
static void startrx (u1_t rxmode) {
|
||||
ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
|
||||
if(getSf(LMIC.rps) == FSK) { // FSK modem
|
||||
rxfsk(rxmode);
|
||||
} else { // LoRa modem
|
||||
rxlora(rxmode);
|
||||
}
|
||||
// the radio will go back to STANDBY mode as soon as the RX is finished
|
||||
// or timed out, and the corresponding IRQ will inform us about completion.
|
||||
}
|
||||
|
||||
// get random seed from wideband noise rssi
|
||||
void radio_init () {
|
||||
hal_disableIRQs();
|
||||
|
||||
// manually reset radio
|
||||
#ifdef CFG_sx1276_radio
|
||||
hal_pin_rst(0); // drive RST pin low
|
||||
#else
|
||||
hal_pin_rst(1); // drive RST pin high
|
||||
#endif
|
||||
hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us
|
||||
hal_pin_rst(2); // configure RST pin floating!
|
||||
hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms
|
||||
|
||||
opmode(OPMODE_SLEEP);
|
||||
|
||||
// some sanity checks, e.g., read version number
|
||||
u1_t v = readReg(RegVersion);
|
||||
#ifdef CFG_sx1276_radio
|
||||
ASSERT(v == 0x12 );
|
||||
#elif CFG_sx1272_radio
|
||||
ASSERT(v == 0x22);
|
||||
#else
|
||||
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
|
||||
#endif
|
||||
// seed 15-byte randomness via noise rssi
|
||||
rxlora(RXMODE_RSSI);
|
||||
while( (readReg(RegOpMode) & OPMODE_MASK) != OPMODE_RX ); // continuous rx
|
||||
for(int i=1; i<16; i++) {
|
||||
for(int j=0; j<8; j++) {
|
||||
u1_t b; // wait for two non-identical subsequent least-significant bits
|
||||
while( (b = readReg(LORARegRssiWideband) & 0x01) == (readReg(LORARegRssiWideband) & 0x01) );
|
||||
randbuf[i] = (randbuf[i] << 1) | b;
|
||||
}
|
||||
}
|
||||
randbuf[0] = 16; // set initial index
|
||||
|
||||
#ifdef CFG_sx1276mb1_board
|
||||
// chain calibration
|
||||
writeReg(RegPaConfig, 0);
|
||||
|
||||
// Launch Rx chain calibration for LF band
|
||||
writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
|
||||
while((readReg(FSKRegImageCal)&RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING){ ; }
|
||||
|
||||
// Sets a Frequency in HF band
|
||||
u4_t frf = 868000000;
|
||||
writeReg(RegFrfMsb, (u1_t)(frf>>16));
|
||||
writeReg(RegFrfMid, (u1_t)(frf>> 8));
|
||||
writeReg(RegFrfLsb, (u1_t)(frf>> 0));
|
||||
|
||||
// Launch Rx chain calibration for HF band
|
||||
writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
|
||||
while((readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING) { ; }
|
||||
#endif /* CFG_sx1276mb1_board */
|
||||
|
||||
opmode(OPMODE_SLEEP);
|
||||
|
||||
hal_enableIRQs();
|
||||
}
|
||||
|
||||
// return next random byte derived from seed buffer
|
||||
// (buf[0] holds index of next byte to be returned)
|
||||
u1_t radio_rand1 () {
|
||||
u1_t i = randbuf[0];
|
||||
ASSERT( i != 0 );
|
||||
if( i==16 ) {
|
||||
os_aes(AES_ENC, randbuf, 16); // encrypt seed with any key
|
||||
i = 0;
|
||||
}
|
||||
u1_t v = randbuf[i++];
|
||||
randbuf[0] = i;
|
||||
return v;
|
||||
}
|
||||
|
||||
u1_t radio_rssi () {
|
||||
hal_disableIRQs();
|
||||
u1_t r = readReg(LORARegRssiValue);
|
||||
hal_enableIRQs();
|
||||
return r;
|
||||
}
|
||||
|
||||
static CONST_TABLE(u2_t, LORA_RXDONE_FIXUP)[] = {
|
||||
[FSK] = us2osticks(0), // ( 0 ticks)
|
||||
[SF7] = us2osticks(0), // ( 0 ticks)
|
||||
[SF8] = us2osticks(1648), // ( 54 ticks)
|
||||
[SF9] = us2osticks(3265), // ( 107 ticks)
|
||||
[SF10] = us2osticks(7049), // ( 231 ticks)
|
||||
[SF11] = us2osticks(13641), // ( 447 ticks)
|
||||
[SF12] = us2osticks(31189), // (1022 ticks)
|
||||
};
|
||||
|
||||
// called by hal ext IRQ handler
|
||||
// (radio goes to stanby mode after tx/rx operations)
|
||||
void radio_irq_handler (u1_t dio) {
|
||||
ostime_t now = os_getTime();
|
||||
if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem
|
||||
u1_t flags = readReg(LORARegIrqFlags);
|
||||
#if LMIC_DEBUG_LEVEL > 1
|
||||
lmic_printf("%lu: irq: dio: 0x%x flags: 0x%x\n", now, dio, flags);
|
||||
#endif
|
||||
if( flags & IRQ_LORA_TXDONE_MASK ) {
|
||||
// save exact tx time
|
||||
LMIC.txend = now - us2osticks(43); // TXDONE FIXUP
|
||||
} else if( flags & IRQ_LORA_RXDONE_MASK ) {
|
||||
// save exact rx time
|
||||
if(getBw(LMIC.rps) == BW125) {
|
||||
now -= TABLE_GET_U2(LORA_RXDONE_FIXUP, getSf(LMIC.rps));
|
||||
}
|
||||
LMIC.rxtime = now;
|
||||
// read the PDU and inform the MAC that we received something
|
||||
LMIC.dataLen = (readReg(LORARegModemConfig1) & SX1272_MC1_IMPLICIT_HEADER_MODE_ON) ?
|
||||
readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes);
|
||||
// set FIFO read address pointer
|
||||
writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr));
|
||||
// now read the FIFO
|
||||
readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
|
||||
// read rx quality parameters
|
||||
LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
|
||||
LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63)
|
||||
} else if( flags & IRQ_LORA_RXTOUT_MASK ) {
|
||||
// indicate timeout
|
||||
LMIC.dataLen = 0;
|
||||
}
|
||||
// mask all radio IRQs
|
||||
writeReg(LORARegIrqFlagsMask, 0xFF);
|
||||
// clear radio IRQ flags
|
||||
writeReg(LORARegIrqFlags, 0xFF);
|
||||
} else { // FSK modem
|
||||
u1_t flags1 = readReg(FSKRegIrqFlags1);
|
||||
u1_t flags2 = readReg(FSKRegIrqFlags2);
|
||||
if( flags2 & IRQ_FSK2_PACKETSENT_MASK ) {
|
||||
// save exact tx time
|
||||
LMIC.txend = now;
|
||||
} else if( flags2 & IRQ_FSK2_PAYLOADREADY_MASK ) {
|
||||
// save exact rx time
|
||||
LMIC.rxtime = now;
|
||||
// read the PDU and inform the MAC that we received something
|
||||
LMIC.dataLen = readReg(FSKRegPayloadLength);
|
||||
// now read the FIFO
|
||||
readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
|
||||
// read rx quality parameters
|
||||
LMIC.snr = 0; // determine snr
|
||||
LMIC.rssi = 0; // determine rssi
|
||||
} else if( flags1 & IRQ_FSK1_TIMEOUT_MASK ) {
|
||||
// indicate timeout
|
||||
LMIC.dataLen = 0;
|
||||
} else {
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
// go from stanby to sleep
|
||||
opmode(OPMODE_SLEEP);
|
||||
// run os job (use preset func ptr)
|
||||
os_setCallback(&LMIC.osjob, LMIC.osjob.func);
|
||||
}
|
||||
|
||||
void os_radio (u1_t mode) {
|
||||
hal_disableIRQs();
|
||||
switch (mode) {
|
||||
case RADIO_RST:
|
||||
// put radio to sleep
|
||||
opmode(OPMODE_SLEEP);
|
||||
break;
|
||||
|
||||
case RADIO_TX:
|
||||
// transmit frame now
|
||||
starttx(); // buf=LMIC.frame, len=LMIC.dataLen
|
||||
break;
|
||||
|
||||
case RADIO_RX:
|
||||
// receive frame now (exactly at rxtime)
|
||||
startrx(RXMODE_SINGLE); // buf=LMIC.frame, time=LMIC.rxtime, timeout=LMIC.rxsyms
|
||||
break;
|
||||
|
||||
case RADIO_RXON:
|
||||
// start scanning for beacon now
|
||||
startrx(RXMODE_SCAN); // buf=LMIC.frame
|
||||
break;
|
||||
}
|
||||
hal_enableIRQs();
|
||||
}
|
36
lib/readme.txt
Normal file
36
lib/readme.txt
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
This directory is intended for the project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link to executable file.
|
||||
|
||||
The source code of each library should be placed in separate directory, like
|
||||
"lib/private_lib/[here are source files]".
|
||||
|
||||
For example, see how can be organized `Foo` and `Bar` libraries:
|
||||
|
||||
|--lib
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |- readme.txt --> THIS FILE
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
Then in `src/main.c` you should use:
|
||||
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
// rest H/C/CPP code
|
||||
|
||||
PlatformIO will find your libraries automatically, configure preprocessor's
|
||||
include paths and build them.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- http://docs.platformio.org/page/librarymanager/ldf.html
|
97
platformio.ini
Normal file
97
platformio.ini
Normal file
@ -0,0 +1,97 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; http://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
env_default = heltec_wifi_lora_32
|
||||
;env_default = ttgo
|
||||
;env_default = lopy
|
||||
;env_default = lopy4
|
||||
|
||||
[env:heltec_wifi_lora_32]
|
||||
platform = espressif32
|
||||
board = heltec_wifi_lora_32
|
||||
framework = arduino
|
||||
monitor_baud = 115200
|
||||
lib_deps = U8g2
|
||||
build_flags =
|
||||
;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework
|
||||
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE
|
||||
;needed for ESP32 BLE Ardunio v0.4.9
|
||||
-fexceptions
|
||||
-std=c++11
|
||||
;override lora settings from LMiC library in lmic/config.h and use main.h instead
|
||||
-D_lmic_config_h_
|
||||
-include "src/main.h"
|
||||
-include "src/hal/heltec.h"
|
||||
;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp)
|
||||
; -DCONFIG_FREERTOS_UNICORE
|
||||
|
||||
[env:ttgo]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_baud = 115200
|
||||
lib_deps = U8g2
|
||||
build_flags =
|
||||
;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework
|
||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE
|
||||
;needed for ESP32 BLE Ardunio v0.4.9
|
||||
-fexceptions
|
||||
-std=c++11
|
||||
;override lora settings from LMiC library in lmic/config.h and use main.h instead
|
||||
-D_lmic_config_h_
|
||||
-include "src/main.h"
|
||||
-include "src/hal/ttgo.h"
|
||||
;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp)
|
||||
; -DCONFIG_FREERTOS_UNICORE
|
||||
|
||||
[env:lopy]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_baud = 115200
|
||||
lib_deps = U8g2@>2.21.7
|
||||
build_flags =
|
||||
;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework
|
||||
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE
|
||||
;needed for ESP32 BLE Ardunio v0.4.9
|
||||
-fexceptions
|
||||
-std=c++11
|
||||
;override lora settings from LMiC library in lmic/config.h and use main.h instead
|
||||
-D_lmic_config_h_
|
||||
-include "src/main.h"
|
||||
-include "src/hal/antenna.h"
|
||||
-include "src/hal/lopy.h"
|
||||
;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp)
|
||||
; -DCONFIG_FREERTOS_UNICORE
|
||||
|
||||
[env:lopy4]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_baud = 115200
|
||||
lib_deps = U8g2@>2.21.7
|
||||
build_flags =
|
||||
;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework
|
||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE
|
||||
;needed for ESP32 BLE Ardunio v0.4.9
|
||||
-fexceptions
|
||||
-std=c++11
|
||||
;override lora settings from LMiC library in lmic/config.h and use main.h instead
|
||||
-D_lmic_config_h_
|
||||
-include "src/main.h"
|
||||
-include "src/hal/antenna.h"
|
||||
-include "src/hal/lopy4.h"
|
||||
;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp)
|
||||
; -DCONFIG_FREERTOS_UNICORE
|
37
src/antenna.cpp
Normal file
37
src/antenna.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#ifdef LOPY
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Local logging tag
|
||||
static const char *TAG = "antenna";
|
||||
|
||||
static antenna_type_t antenna_type_selected = ANTENNA_TYPE_INTERNAL;
|
||||
|
||||
void antenna_init(void) {
|
||||
gpio_config_t gpioconf = {.pin_bit_mask = 1ull << PIN_ANTENNA_SWITCH,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE};
|
||||
gpio_config(&gpioconf);
|
||||
}
|
||||
|
||||
void antenna_select (antenna_type_t _antenna) {
|
||||
if (PIN_ANTENNA_SWITCH < 32) {
|
||||
// set the pin value
|
||||
if (_antenna == ANTENNA_TYPE_EXTERNAL) {
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1 << PIN_ANTENNA_SWITCH);
|
||||
} else {
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, 1 << PIN_ANTENNA_SWITCH);
|
||||
}
|
||||
} else {
|
||||
if (_antenna == ANTENNA_TYPE_EXTERNAL) {
|
||||
GPIO_REG_WRITE(GPIO_OUT1_W1TS_REG, 1 << (PIN_ANTENNA_SWITCH & 31));
|
||||
} else {
|
||||
GPIO_REG_WRITE(GPIO_OUT1_W1TC_REG, 1 << (PIN_ANTENNA_SWITCH & 31));
|
||||
}
|
||||
}
|
||||
antenna_type_selected = _antenna;
|
||||
}
|
||||
|
||||
#endif //
|
38
src/blecount.cpp
Normal file
38
src/blecount.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
// Log Level magic
|
||||
#include "main.h"
|
||||
|
||||
// not using this seems to break U8X8LIB
|
||||
#include <Arduino.h>
|
||||
|
||||
// Local logging tag
|
||||
static const char *TAG = "blecount";
|
||||
|
||||
// Basic Config
|
||||
#include "globals.h"
|
||||
#include "loraconf.h"
|
||||
|
||||
#ifdef BLECOUNTER
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEScan.h>
|
||||
#include <BLEAdvertisedDevice.h>
|
||||
|
||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
||||
}
|
||||
};
|
||||
|
||||
void BLECount() {
|
||||
u8x8.clearLine(3);
|
||||
u8x8.drawString(0,3,"BLE Scan...");
|
||||
BLEDevice::init("PaxCnt");
|
||||
BLEScan* pBLEScan = BLEDevice::getScan(); //create new scan
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
|
||||
BLEScanResults foundDevices = pBLEScan->start(cfg.blescancycle);
|
||||
u8x8.clearLine(3);
|
||||
u8x8.setCursor(0,3);
|
||||
blenum=foundDevices.getCount();
|
||||
u8x8.printf("BLE#: %4i",blenum);
|
||||
}
|
||||
#endif
|
248
src/configmanager.cpp
Normal file
248
src/configmanager.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
/* configmanager persists runtime configuration using NVRAM of ESP32*/
|
||||
|
||||
#include "globals.h"
|
||||
#include <nvs.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
// Local logging tag
|
||||
static const char *TAG = "configmanager";
|
||||
|
||||
nvs_handle my_handle;
|
||||
|
||||
esp_err_t err;
|
||||
|
||||
// populate cfg vars with factory settings
|
||||
void defaultConfig() {
|
||||
cfg.lorasf = LORASFDEFAULT; // 7-12, initial lora spreadfactor defined in main.h
|
||||
cfg.txpower = 15; // 2-15, lora tx power
|
||||
cfg.adrmode = 1; // 0=disabled, 1=enabled
|
||||
cfg.screensaver = 0; // 0=disabled, 1=enabled
|
||||
cfg.screenon = 1; // 0=disbaled, 1=enabled
|
||||
cfg.countermode = 0; // 0=cyclic, 1=cumulative, 2=cyclic confirmed
|
||||
cfg.rssilimit = 0; // threshold for rssilimiter, negative value!
|
||||
cfg.wifiscancycle = SEND_SECS; // wifi scan cycle [seconds/2]
|
||||
cfg.wifichancycle = WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100]
|
||||
cfg.blescancycle = BLESCANTIME; // BLE scan cycle [seconds]
|
||||
cfg.blescan = 0; // 0=disabled, 1=enabled
|
||||
strncpy( cfg.version, PROGVERSION, sizeof(cfg.version)-1 );
|
||||
}
|
||||
|
||||
void open_storage() {
|
||||
err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
// NVS partition was truncated and needs to be erased
|
||||
// Retry nvs_flash_init
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( err );
|
||||
|
||||
// Open
|
||||
ESP_LOGI(TAG, "Opening NVS");
|
||||
err = nvs_open("config", NVS_READWRITE, &my_handle);
|
||||
if (err != ESP_OK)
|
||||
ESP_LOGI(TAG, "Error (%d) opening NVS handle", err);
|
||||
else
|
||||
ESP_LOGI(TAG, "Done");
|
||||
}
|
||||
|
||||
// erase all keys and values in NVRAM
|
||||
void eraseConfig() {
|
||||
ESP_LOGI(TAG, "Clearing settings in NVS");
|
||||
open_storage();
|
||||
if (err == ESP_OK) {
|
||||
nvs_erase_all(my_handle);
|
||||
nvs_commit(my_handle);
|
||||
nvs_close(my_handle);
|
||||
ESP_LOGI(TAG, "Done");}
|
||||
else {
|
||||
ESP_LOGW(TAG, "NVS erase failed"); }
|
||||
}
|
||||
|
||||
// save current configuration from RAM to NVRAM
|
||||
void saveConfig() {
|
||||
ESP_LOGI(TAG, "Storing settings in NVS");
|
||||
open_storage();
|
||||
if (err == ESP_OK) {
|
||||
int8_t flash8 = 0;
|
||||
int16_t flash16 = 0;
|
||||
size_t required_size;
|
||||
char storedversion[10];
|
||||
|
||||
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);
|
||||
|
||||
if( nvs_get_i8(my_handle, "lorasf", &flash8) != ESP_OK || flash8 != cfg.lorasf )
|
||||
nvs_set_i8(my_handle, "lorasf", cfg.lorasf);
|
||||
|
||||
if( nvs_get_i8(my_handle, "txpower", &flash8) != ESP_OK || flash8 != cfg.txpower )
|
||||
nvs_set_i8(my_handle, "txpower", cfg.txpower);
|
||||
|
||||
if( nvs_get_i8(my_handle, "adrmode", &flash8) != ESP_OK || flash8 != cfg.adrmode )
|
||||
nvs_set_i8(my_handle, "adrmode", cfg.adrmode);
|
||||
|
||||
if( nvs_get_i8(my_handle, "screensaver", &flash8) != ESP_OK || flash8 != cfg.screensaver )
|
||||
nvs_set_i8(my_handle, "screensaver", cfg.screensaver);
|
||||
|
||||
if( nvs_get_i8(my_handle, "screenon", &flash8) != ESP_OK || flash8 != cfg.screenon )
|
||||
nvs_set_i8(my_handle, "screenon", cfg.screenon);
|
||||
|
||||
if( nvs_get_i8(my_handle, "countermode", &flash8) != ESP_OK || flash8 != cfg.countermode )
|
||||
nvs_set_i8(my_handle, "countermode", cfg.countermode);
|
||||
|
||||
if( nvs_get_i8(my_handle, "wifiscancycle", &flash8) != ESP_OK || flash8 != cfg.wifiscancycle )
|
||||
nvs_set_i8(my_handle, "wifiscancycle", cfg.wifiscancycle);
|
||||
|
||||
if( nvs_get_i8(my_handle, "wifichancycle", &flash8) != ESP_OK || flash8 != cfg.wifichancycle )
|
||||
nvs_set_i8(my_handle, "wifichancycle", cfg.wifichancycle);
|
||||
|
||||
if( nvs_get_i8(my_handle, "blescancycle", &flash8) != ESP_OK || flash8 != cfg.blescancycle )
|
||||
nvs_set_i8(my_handle, "blescancycle", cfg.blescancycle);
|
||||
|
||||
if( nvs_get_i8(my_handle, "blescanmode", &flash8) != ESP_OK || flash8 != cfg.blescan )
|
||||
nvs_set_i8(my_handle, "blescanmode", cfg.blescan);
|
||||
|
||||
if( nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK || flash16 != cfg.rssilimit )
|
||||
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
|
||||
|
||||
err = nvs_commit(my_handle);
|
||||
nvs_close(my_handle);
|
||||
if ( err == ESP_OK ) {
|
||||
ESP_LOGI(TAG, "Done");
|
||||
} else {
|
||||
ESP_LOGW(TAG, "NVS config write failed");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Error (%d) opening NVS handle", err);
|
||||
}
|
||||
}
|
||||
|
||||
// set and save cfg.version
|
||||
void migrateVersion() {
|
||||
sprintf(cfg.version, "%s", PROGVERSION);
|
||||
ESP_LOGI(TAG, "version set to %s", cfg.version);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
// load configuration from NVRAM into RAM and make it current
|
||||
void loadConfig() {
|
||||
defaultConfig(); // start with factory settings
|
||||
ESP_LOGI(TAG, "Reading settings from NVS");
|
||||
open_storage();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG,"Error (%d) opening NVS handle, storing defaults", err);
|
||||
saveConfig(); } // saves factory settings to NVRAM
|
||||
else {
|
||||
int8_t flash8 = 0;
|
||||
int16_t flash16 = 0;
|
||||
size_t required_size;
|
||||
|
||||
// check if configuration stored in NVRAM matches PROGVERSION
|
||||
if( nvs_get_str(my_handle, "version", NULL, &required_size) == ESP_OK ) {
|
||||
nvs_get_str(my_handle, "version", cfg.version, &required_size);
|
||||
ESP_LOGI(TAG, "NVRAM settings version = %s", cfg.version);
|
||||
if (strcmp(cfg.version, PROGVERSION)) {
|
||||
ESP_LOGI(TAG, "migrating NVRAM settings to new version %s", PROGVERSION);
|
||||
nvs_close(my_handle);
|
||||
migrateVersion();
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(TAG, "new version %s, deleting NVRAM settings", PROGVERSION);
|
||||
nvs_close(my_handle);
|
||||
eraseConfig();
|
||||
migrateVersion();
|
||||
}
|
||||
|
||||
// overwrite defaults with valid values from NVRAM
|
||||
if( nvs_get_i8(my_handle, "lorasf", &flash8) == ESP_OK ) {
|
||||
cfg.lorasf = flash8;
|
||||
ESP_LOGI(TAG, "lorasf = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "lorasf set to default %i", cfg.lorasf);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "txpower", &flash8) == ESP_OK ) {
|
||||
cfg.txpower = flash8;
|
||||
ESP_LOGI(TAG, "txpower = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "txpower set to default %i", cfg.txpower);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "adrmode", &flash8) == ESP_OK ) {
|
||||
cfg.adrmode = flash8;
|
||||
ESP_LOGI(TAG, "adrmode = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "adrmode set to default %i", cfg.adrmode);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "screensaver", &flash8) == ESP_OK ) {
|
||||
cfg.screensaver = flash8;
|
||||
ESP_LOGI(TAG, "screensaver = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "screensaver set to default %i", cfg.screensaver);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "screenon", &flash8) == ESP_OK ) {
|
||||
cfg.screenon = flash8;
|
||||
ESP_LOGI(TAG, "screenon = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "screenon set to default %i", cfg.screenon);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "countermode", &flash8) == ESP_OK ) {
|
||||
cfg.countermode = flash8;
|
||||
ESP_LOGI(TAG, "countermode = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "countermode set to default %i", cfg.countermode);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "wifiscancycle", &flash8) == ESP_OK ) {
|
||||
cfg.wifiscancycle = flash8;
|
||||
ESP_LOGI(TAG, "wifiscancycle = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "WIFI scan cycle set to default %i", cfg.wifiscancycle);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "wifichancycle", &flash8) == ESP_OK ) {
|
||||
cfg.wifichancycle = flash8;
|
||||
ESP_LOGI(TAG, "wifichancycle = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "WIFI channel cycle set to default %i", cfg.wifichancycle);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "blescancycle", &flash8) == ESP_OK ) {
|
||||
cfg.blescancycle = flash8;
|
||||
ESP_LOGI(TAG, "blescancycle = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BLEscan cycle set to default %i", cfg.blescancycle);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i8(my_handle, "blescanmode", &flash8) == ESP_OK ) {
|
||||
cfg.blescan = flash8;
|
||||
ESP_LOGI(TAG, "BLEscanmode = %i", flash8);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BLEscanmode set to default %i", cfg.blescan);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
if( nvs_get_i16(my_handle, "rssilimit", &flash16) == ESP_OK ) {
|
||||
cfg.rssilimit = flash16;
|
||||
ESP_LOGI(TAG, "rssilimit = %i", flash16);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "rssilimit set to default %i", cfg.rssilimit);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
nvs_close(my_handle);
|
||||
ESP_LOGI(TAG, "Done");
|
||||
}
|
||||
}
|
16
src/configmanager.h
Normal file
16
src/configmanager.h
Normal file
@ -0,0 +1,16 @@
|
||||
/* struct holding devices's runtime configuration */
|
||||
|
||||
typedef struct {
|
||||
int8_t lorasf; // 7-12, lora spreadfactor
|
||||
int8_t txpower; // 2-15, lora tx power
|
||||
int8_t adrmode; // 0=disabled, 1=enabled
|
||||
int8_t screensaver; // 0=disabled, 1=enabled
|
||||
int8_t screenon; // 0=disabled, 1=enabled
|
||||
int8_t countermode; // 0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed
|
||||
int16_t rssilimit; // threshold for rssilimiter, negative value!
|
||||
int8_t wifiscancycle; // wifi scan cycle [seconds/2]
|
||||
int8_t wifichancycle; // wifi channel switch cycle [seconds/100]
|
||||
int8_t blescancycle; // BLE scan cycle [seconds]
|
||||
int8_t blescan; // 0=disabled, 1=enabled
|
||||
char version[10]; // Firmware version
|
||||
} configData_t;
|
40
src/globals.h
Normal file
40
src/globals.h
Normal file
@ -0,0 +1,40 @@
|
||||
// First things first
|
||||
#include "main.h"
|
||||
|
||||
// The mother of all embedded development...
|
||||
#include <Arduino.h>
|
||||
|
||||
// we neededthis to ESP_LOGx on arduino framework
|
||||
#include "esp32-hal-log.h"
|
||||
|
||||
#include <String.h>
|
||||
|
||||
// std::set for unified array functions
|
||||
#include <set>
|
||||
|
||||
// OLED Display
|
||||
#include <U8x8lib.h>
|
||||
|
||||
// LMIC-Arduino LoRaWAN Stack
|
||||
#include <lmic.h>
|
||||
#include <hal/hal.h>
|
||||
|
||||
// configData_t
|
||||
#include "configmanager.h"
|
||||
|
||||
extern uint8_t mydata[];
|
||||
extern uint64_t uptimecounter;
|
||||
extern int macnum, blenum, countermode, screensaver, adrmode, lorasf, txpower, rlim;
|
||||
extern bool joinstate;
|
||||
|
||||
extern osjob_t sendjob;
|
||||
|
||||
extern std::set<uint64_t, std::greater <uint64_t> > macs;
|
||||
|
||||
extern U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8;
|
||||
|
||||
extern configData_t cfg;
|
||||
|
||||
#ifdef BLECOUNTER
|
||||
extern int scanTime;
|
||||
#endif
|
21
src/hal/antenna.h
Normal file
21
src/hal/antenna.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Pycom Limited.
|
||||
*
|
||||
* This software is licensed under the GNU GPL version 3 or any
|
||||
* later version, with permitted additional terms. For more information
|
||||
* see the Pycom Licence v1.0 document supplied with this file, or
|
||||
* available at https://www.pycom.io/opensource/licensing
|
||||
*/
|
||||
|
||||
#ifndef _ANTENNA_H_
|
||||
#define _ANTENNA_H_
|
||||
|
||||
typedef enum {
|
||||
ANTENNA_TYPE_INTERNAL = 0,
|
||||
ANTENNA_TYPE_EXTERNAL
|
||||
} antenna_type_t;
|
||||
|
||||
extern void antenna_init (void);
|
||||
extern void antenna_select (antenna_type_t antenna_type);
|
||||
|
||||
#endif /* _ANTENNA_H_ */
|
24
src/hal/heltec.h
Normal file
24
src/hal/heltec.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Hardware related definitions for Heltec LoRa-32 Board
|
||||
|
||||
#define HELTEC
|
||||
#define HAS_DISPLAY // has OLED-Display
|
||||
#define HAS_LED // has on usable board LED
|
||||
#define HAS_BUTTON // has onboard button
|
||||
#define CFG_sx1276_radio 1
|
||||
|
||||
// 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_MOSI 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_SCK 5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
|
||||
|
||||
// non arduino pin definitions
|
||||
#define RST 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 DIO1 33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
|
||||
#define DIO2 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
|
||||
#define OLED_RST 16 // ESP32 GPIO16 (Pin16) -- SD1306 Reset
|
||||
#define OLED_SDA 4 // ESP32 GPIO4 (Pin4) -- SD1306 Data
|
||||
#define OLED_SCL 15 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
|
18
src/hal/lopy.h
Normal file
18
src/hal/lopy.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Hardware related definitions for Pycom LoPy Board (not: LoPy4)
|
||||
|
||||
#define LOPY
|
||||
#define CFG_sx1272_radio 1
|
||||
|
||||
// Hardware pin definitions for Pycom LoPy board
|
||||
#define PIN_SPI_SS 17
|
||||
#define PIN_SPI_MOSI 27
|
||||
#define PIN_SPI_MISO 19
|
||||
#define PIN_SPI_SCK 5
|
||||
#define RST 18
|
||||
#define DIO0 23 // LoRa IRQ
|
||||
#define DIO1 23 // workaround
|
||||
#define DIO2 23 // workaround
|
||||
|
||||
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
||||
#define PIN_ANTENNA_SWITCH 16
|
||||
#define WIFI_LOPY_ANTENNA ANTENNA_TYPE_INTERNAL
|
18
src/hal/lopy4.h
Normal file
18
src/hal/lopy4.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Hardware related definitions for Pycom LoPy Board (not: LoPy4)
|
||||
|
||||
#define LOPY
|
||||
#define CFG_sx1276_radio 1
|
||||
|
||||
// Hardware pin definitions for Pycom LoPy4 board
|
||||
#define PIN_SPI_SS 18
|
||||
#define PIN_SPI_MOSI 27
|
||||
#define PIN_SPI_MISO 19
|
||||
#define PIN_SPI_SCK 5
|
||||
#define RST LMIC_UNUSED_PIN
|
||||
#define DIO0 23 // LoRa IRQ
|
||||
#define DIO1 23 // workaround
|
||||
#define DIO2 23 // workaround
|
||||
|
||||
// select WIFI antenna (internal = onboard / external = u.fl socket)
|
||||
#define PIN_ANTENNA_SWITCH 21
|
||||
#define WIFI_LOPY_ANTENNA ANTENNA_TYPE_INTERNAL
|
48
src/hal/ttgo.h
Normal file
48
src/hal/ttgo.h
Normal file
@ -0,0 +1,48 @@
|
||||
// Hardware related definitions for TTGO V2 Board
|
||||
|
||||
#define TTGO
|
||||
#define HAS_DISPLAY // has OLED-Display
|
||||
#define CFG_sx1276_radio 1
|
||||
|
||||
// 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_MOSI 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_SCK 5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
|
||||
|
||||
// non arduino pin definitions
|
||||
#define RST LMIC_UNUSED_PIN // not sure
|
||||
#define DIO0 26 // wired on PCB
|
||||
#define DIO1 33 // needs to be wired external
|
||||
#define DIO2 32 // needs to be wired external (but not necessary for LoRa)
|
||||
|
||||
// Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display
|
||||
#define OLED_RST U8X8_PIN_NONE // to be checked if really not connected
|
||||
#define OLED_SDA 21 // ESP32 GPIO4 (Pin4) -- SD1306 Data
|
||||
#define OLED_SCL 22 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
|
||||
|
||||
|
||||
/*
|
||||
ESP32 LoRa module (SPI) OLED display (I2C)
|
||||
--------- ----------------- ------------------
|
||||
5 SCK SCK
|
||||
27 MOSI MOSI
|
||||
19 MISO MISO
|
||||
18 SS NSS
|
||||
14 RST
|
||||
26 DIO0
|
||||
33 DIO1 (see note {1})
|
||||
32 DIO2 (see note {2})
|
||||
22 SCL SCL
|
||||
21 SDA SDA
|
||||
22 LED (useless, see note {3})
|
||||
|
||||
{1} Must be manually wired!
|
||||
DIO1 is wired to a separate pin but is not wired on-board to pin/GPIO33.
|
||||
Explicitly wire board pin labeled DIO1 to pin 33 (see TTGO V2.0 pinout).
|
||||
{2} Must be manually wired!
|
||||
DIO2 is wired to a separate pin but is not wired on-board to pin/GPIO32.
|
||||
Explicitly wire board pin labeled DIO2 to pin 32 (see TTGO V2.0 pinout).
|
||||
{3} The on-board LED is wired to SCL (used by display) therefore totally useless!
|
||||
*/
|
||||
|
29
src/loraconf.sample.h
Normal file
29
src/loraconf.sample.h
Normal file
@ -0,0 +1,29 @@
|
||||
/************************************************************
|
||||
* LMIC LoRaWAN configuration
|
||||
*
|
||||
* Read the values from TTN console (or whatever applies)
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/*
|
||||
|
||||
// Only define DEVEUI here if you don't want it to be derived from device's MAC address
|
||||
// Use little endian format (lsb)
|
||||
|
||||
//static const u1_t DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
// This EUI must be in little-endian format, so least-significant-byte
|
||||
// first. When copying an EUI from ttnctl output, this means to reverse
|
||||
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
|
||||
// 0x70.
|
||||
static const u1_t APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xB3, 0x70 };
|
||||
|
||||
// This key should be in big endian format (or, since it is not really a
|
||||
// number but a block of memory, endianness does not really apply). In
|
||||
// practice, a key taken from ttnctl can be copied as-is.
|
||||
// The key shown here is the semtech default key.
|
||||
static const u1_t APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
*/
|
220
src/lorawan.cpp
Normal file
220
src/lorawan.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
|
||||
// Basic Config
|
||||
#include "main.h"
|
||||
// #include <Arduino.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "loraconf.h"
|
||||
|
||||
// LMIC-Arduino LoRaWAN Stack
|
||||
#include <lmic.h>
|
||||
#include <hal/hal.h>
|
||||
|
||||
// needs to be defined here
|
||||
uint8_t mydata[] = "0000";
|
||||
|
||||
// Local logging Tag
|
||||
static const char *TAG = "lorawan";
|
||||
|
||||
// function defined in main.cpp
|
||||
void set_onboard_led(int state);
|
||||
|
||||
// functions defined in rcommand.cpp
|
||||
void rcommand(int cmd, int arg);
|
||||
void switch_lora(int sf, int tx);
|
||||
|
||||
// DevEUI generator using devices's MAC address
|
||||
void gen_lora_deveui(uint8_t *pdeveui) {
|
||||
uint8_t *p = pdeveui, dmac[6];
|
||||
int i = 0;
|
||||
esp_efuse_mac_get_default(dmac);
|
||||
// deveui is LSB, we reverse it so TTN DEVEUI display
|
||||
// will remain the same as MAC address
|
||||
// MAC is 6 bytes, devEUI 8, set first 2 ones
|
||||
// with an arbitrary value
|
||||
*p++ = 0xFF;
|
||||
*p++ = 0xFE;
|
||||
// Then next 6 bytes are mac address reversed
|
||||
for ( i=0; i<6 ; i++) {
|
||||
*p++ = dmac[5-i];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
|
||||
// Display a key
|
||||
void printKey(const char * name, const uint8_t * key, uint8_t len, bool lsb) {
|
||||
uint8_t start=lsb?len:0;
|
||||
uint8_t end = lsb?0:len;
|
||||
const uint8_t * p ;
|
||||
char keystring[len+1] = "", keybyte[3];
|
||||
for (uint8_t i=0; i<len ; i++) {
|
||||
p = lsb ? key+len-i-1 : key+i;
|
||||
sprintf(keybyte, "%02X", * p);
|
||||
strncat(keystring, keybyte, 2);
|
||||
}
|
||||
ESP_LOGI(TAG, "%s: %s", name, keystring);
|
||||
}
|
||||
|
||||
// Display OTAA keys
|
||||
void printKeys(void) {
|
||||
// LMIC may not have used callback to fill
|
||||
// all EUI buffer so we do it here to a temp
|
||||
// buffer to be able to display them
|
||||
uint8_t buf[32];
|
||||
os_getDevEui((u1_t*) buf);
|
||||
printKey("DevEUI", buf, 8, true);
|
||||
os_getArtEui((u1_t*) buf);
|
||||
printKey("AppEUI", buf, 8, true);
|
||||
os_getDevKey((u1_t*) buf);
|
||||
printKey("AppKey", buf, 16, false);
|
||||
}
|
||||
|
||||
#endif // VERBOSE
|
||||
|
||||
void do_send(osjob_t* j){
|
||||
mydata[0] = (macnum & 0x0000ff00) >> 8;
|
||||
mydata[1] = macnum & 0x000000ff;
|
||||
mydata[2] = (blenum & 0x0000ff00) >> 8;
|
||||
mydata[3] = blenum & 0x000000ff;
|
||||
|
||||
// Check if there is not a current TX/RX job running
|
||||
if (LMIC.opmode & OP_TXRXPEND) {
|
||||
ESP_LOGI(TAG, "OP_TXRXPEND, not sending");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "LORA BUSY");
|
||||
} else {
|
||||
// Prepare upstream data transmission at the next possible time.
|
||||
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, (cfg.countermode & 0x02));
|
||||
ESP_LOGI(TAG, "Packet queued");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "PACKET QUEUED");
|
||||
set_onboard_led(1);
|
||||
}
|
||||
// Next TX is scheduled after TX_COMPLETE event.
|
||||
}
|
||||
|
||||
void onEvent (ev_t ev) {
|
||||
switch(ev) {
|
||||
case EV_SCAN_TIMEOUT:
|
||||
ESP_LOGI(TAG, "EV_SCAN_TIMEOUT");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "SCAN TIMEOUT");
|
||||
break;
|
||||
case EV_BEACON_FOUND:
|
||||
ESP_LOGI(TAG, "EV_BEACON_FOUND");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "BEACON FOUND");
|
||||
break;
|
||||
case EV_BEACON_MISSED:
|
||||
ESP_LOGI(TAG, "EV_BEACON_MISSED");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "BEACON MISSED");
|
||||
break;
|
||||
case EV_BEACON_TRACKED:
|
||||
ESP_LOGI(TAG, "EV_BEACON_TRACKED");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "BEACON TRACKED");
|
||||
break;
|
||||
case EV_JOINING:
|
||||
ESP_LOGI(TAG, "EV_JOINING");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "JOINING");
|
||||
break;
|
||||
case EV_JOINED:
|
||||
ESP_LOGI(TAG, "EV_JOINED");
|
||||
u8x8.clearLine(6); // erase "Join Wait" message from display, see main.cpp
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "JOINED");
|
||||
// Disable link check validation (automatically enabled
|
||||
// during join, but not supported by TTN at this time).
|
||||
LMIC_setLinkCheckMode(0);
|
||||
// set data rate adaptation
|
||||
LMIC_setAdrMode(cfg.adrmode);
|
||||
// Set data rate and transmit power (note: txpower seems to be ignored by the library)
|
||||
switch_lora(cfg.lorasf,cfg.txpower);
|
||||
joinstate=true;
|
||||
// show effective LoRa parameters after join
|
||||
ESP_LOGI(TAG, "ADR=%i, SF=%i, TXPOWER=%i", cfg.adrmode, cfg.lorasf, cfg.txpower);
|
||||
break;
|
||||
case EV_RFU1:
|
||||
ESP_LOGI(TAG, "EV_RFU1");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "RFUI");
|
||||
break;
|
||||
case EV_JOIN_FAILED:
|
||||
ESP_LOGI(TAG, "EV_JOIN_FAILED");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "JOIN FAILED");
|
||||
break;
|
||||
case EV_REJOIN_FAILED:
|
||||
ESP_LOGI(TAG, "EV_REJOIN_FAILED");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "REJOIN FAILED");
|
||||
break;
|
||||
case EV_TXCOMPLETE:
|
||||
ESP_LOGI(TAG, "EV_TXCOMPLETE (includes waiting for RX windows)");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "TX COMPLETE");
|
||||
set_onboard_led(0);
|
||||
if (LMIC.txrxFlags & TXRX_ACK) {
|
||||
ESP_LOGI(TAG, "Received ack");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "RECEIVED ACK");
|
||||
}
|
||||
if (LMIC.dataLen) {
|
||||
ESP_LOGI(TAG, "Received %i bytes of payload", LMIC.dataLen);
|
||||
u8x8.clearLine(6);
|
||||
u8x8.setCursor(0, 6);
|
||||
u8x8.printf("Rcvd %i bytes", LMIC.dataLen);
|
||||
u8x8.clearLine(7);
|
||||
u8x8.setCursor(0, 7);
|
||||
// LMIC.snr = SNR twos compliment [dB] * 4
|
||||
// LMIC.rssi = RSSI [dBm] (-196...+63)
|
||||
u8x8.printf("RSSI %d SNR %d", LMIC.rssi, (signed char)LMIC.snr / 4);
|
||||
// check if payload received on command port, then call remote command interpreter
|
||||
if ( (LMIC.txrxFlags & TXRX_PORT) && (LMIC.frame[LMIC.dataBeg-1] == RCMDPORT ) ) {
|
||||
// caution: buffering LMIC values here because rcommand() can modify LMIC.frame
|
||||
unsigned char* buffer = new unsigned char[MAX_LEN_FRAME];
|
||||
memcpy(buffer, LMIC.frame, MAX_LEN_FRAME); //Copy data from cfg to 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;
|
||||
case EV_LOST_TSYNC:
|
||||
ESP_LOGI(TAG, "EV_LOST_TSYNC");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "LOST TSYNC");
|
||||
break;
|
||||
case EV_RESET:
|
||||
ESP_LOGI(TAG, "EV_RESET");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "RESET");
|
||||
break;
|
||||
case EV_RXCOMPLETE:
|
||||
// data received in ping slot
|
||||
ESP_LOGI(TAG, "EV_RXCOMPLETE");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "RX COMPLETE");
|
||||
break;
|
||||
case EV_LINK_DEAD:
|
||||
ESP_LOGI(TAG, "EV_LINK_DEAD");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "LINK DEAD");
|
||||
break;
|
||||
case EV_LINK_ALIVE:
|
||||
ESP_LOGI(TAG, "EV_LINK_ALIVE");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.drawString(0, 7, "LINK ALIVE");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Unknown event");
|
||||
u8x8.clearLine(7);
|
||||
u8x8.setCursor(0, 7);
|
||||
u8x8.printf("UNKNOWN EVENT %d", ev);
|
||||
break;
|
||||
}
|
||||
}
|
424
src/main.cpp
Normal file
424
src/main.cpp
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
*
|
||||
* Oliver Brandmueller <ob@sysadm.in> 2017/2018
|
||||
* Klaus Wilting <verkehrsrot@arcor.de> 2018
|
||||
*
|
||||
* some lines of code taken from:
|
||||
*
|
||||
* Copyright (c) 2017, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
|
||||
* ESP32/016 WiFi Sniffer.
|
||||
* https://github.com/lpodkalicki/blog/tree/master/esp32/016_wifi_sniffer
|
||||
*
|
||||
* Arduino-LMIC Library
|
||||
* TTN OTAA Example
|
||||
* https://github.com/matthijskooijman/arduino-lmic/blob/master/examples/ttn-otaa/
|
||||
*
|
||||
* nkolban esp32 snippets
|
||||
* BLE Scan
|
||||
* https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils/tests/BLETests/Arduino/BLE_scan
|
||||
*
|
||||
* parts of code in lorawan.cpp has been grabbed from RadioHead Library
|
||||
*/
|
||||
|
||||
// First things first
|
||||
#include "main.h"
|
||||
|
||||
// std::set for unified array functions
|
||||
#include <set>
|
||||
|
||||
// OLED driver
|
||||
#include <U8x8lib.h>
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(OLED_RST, OLED_SCL, OLED_SDA);
|
||||
#else
|
||||
U8X8_NULL u8x8;
|
||||
#endif
|
||||
|
||||
// LMIC-Arduino LoRaWAN Stack
|
||||
#include <lmic.h>
|
||||
#include <hal/hal.h>
|
||||
|
||||
// Basic Config
|
||||
#include "loraconf.h"
|
||||
#include "configmanager.h"
|
||||
|
||||
// WiFi Functions
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_wifi_types.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_event_loop.h>
|
||||
#include <esp_spi_flash.h>
|
||||
|
||||
configData_t cfg; // struct holds current device configuration
|
||||
osjob_t sendjob, initjob; // LMIC
|
||||
|
||||
// Initialize global variables
|
||||
int macnum = 0, blenum = 0;
|
||||
uint32_t uptimecounter = 0;
|
||||
bool joinstate = false;
|
||||
extern uint8_t mydata[];
|
||||
|
||||
std::set<uint64_t, std::greater <uint64_t> > macs; // storage holds MAC frames
|
||||
|
||||
// this variable will be changed in the ISR, and read in main loop
|
||||
static volatile bool ButtonTriggered = false;
|
||||
|
||||
// local Tag for logging
|
||||
static const char *TAG = "paxcnt";
|
||||
// Note: Log level control seems working during runtime, so we need to switch loglevel
|
||||
// by compiler build option in platformio.ini
|
||||
#ifndef VERBOSE
|
||||
int redirect_log(const char * fmt, va_list args) {
|
||||
//do nothing
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// defined in configmanager.cpp
|
||||
void eraseConfig(void);
|
||||
void saveConfig(void);
|
||||
void loadConfig(void);
|
||||
|
||||
|
||||
/* begin LMIC specific parts ------------------------------------------------------------ */
|
||||
|
||||
// defined in lorawan.cpp
|
||||
void gen_lora_deveui(uint8_t * pdeveui);
|
||||
#ifdef VERBOSE
|
||||
void printKeys(void);
|
||||
#endif // VERBOSE
|
||||
|
||||
// LMIC callback functions
|
||||
void os_getArtEui (u1_t *buf) { memcpy(buf, APPEUI, 8);}
|
||||
void os_getDevKey (u1_t *buf) { memcpy(buf, APPKEY, 16);}
|
||||
#ifdef DEVEUI // if DEVEUI defined in loraconf.h use that and hardwire it in code ...
|
||||
void os_getDevEui (u1_t *buf) { memcpy(buf, DEVEUI, 8);}
|
||||
#else // ... otherwise generate DEVEUI at runtime from devices's MAC
|
||||
void os_getDevEui (u1_t *buf) { gen_lora_deveui(buf);}
|
||||
#endif
|
||||
|
||||
// LMIC enhanced Pin mapping
|
||||
const lmic_pinmap lmic_pins = {
|
||||
.mosi = PIN_SPI_MOSI,
|
||||
.miso = PIN_SPI_MISO,
|
||||
.sck = PIN_SPI_SCK,
|
||||
.nss = PIN_SPI_SS,
|
||||
.rxtx = LMIC_UNUSED_PIN,
|
||||
.rst = RST,
|
||||
.dio = {DIO0, DIO1, DIO2}
|
||||
};
|
||||
|
||||
// LMIC functions
|
||||
void onEvent(ev_t ev);
|
||||
void do_send(osjob_t* j);
|
||||
|
||||
// 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 Task
|
||||
void lorawan_loop(void * pvParameters) {
|
||||
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
|
||||
while(1) {
|
||||
os_runloop_once();
|
||||
vTaskDelay(10/portTICK_PERIOD_MS);
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
/* end LMIC specific parts --------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* beginn hardware specific parts -------------------------------------------------------- */
|
||||
|
||||
#ifdef LOPY
|
||||
// defined in antenna.cpp
|
||||
void antenna_init (void);
|
||||
void antenna_select (antenna_type_t antenna_type);
|
||||
#endif
|
||||
|
||||
#if defined BLECOUNTER
|
||||
void BLECount(void);
|
||||
#else
|
||||
btStop();
|
||||
#endif
|
||||
|
||||
void set_onboard_led(int st){
|
||||
#ifdef HAS_LED
|
||||
switch (st) {
|
||||
case 1: digitalWrite(LED_BUILTIN, HIGH); break;
|
||||
case 0: digitalWrite(LED_BUILTIN, LOW); break;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
// Button Handling, board dependent -> perhaps to be moved to new hal.cpp
|
||||
// IRAM_ATTR necessary here, see https://github.com/espressif/arduino-esp32/issues/855
|
||||
void IRAM_ATTR isr_button_pressed(void) {
|
||||
ButtonTriggered++; }
|
||||
#endif
|
||||
|
||||
/* end hardware specific parts -------------------------------------------------------- */
|
||||
|
||||
|
||||
/* begin wifi specific parts ---------------------------------------------------------- */
|
||||
|
||||
// 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);
|
||||
|
||||
//WiFi Sniffer Task
|
||||
void wifi_sniffer_loop(void * pvParameters) {
|
||||
|
||||
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
|
||||
uint8_t channel = 1;
|
||||
int nloop=0, lorawait=0;
|
||||
|
||||
while (true) {
|
||||
nloop++;
|
||||
vTaskDelay(cfg.wifichancycle*10 / portTICK_PERIOD_MS);
|
||||
yield();
|
||||
wifi_sniffer_set_channel(channel);
|
||||
channel = (channel % WIFI_CHANNEL_MAX) + 1;
|
||||
|
||||
// duration of one wifi scan loop reached? then send data and begin new scan cycle
|
||||
if( nloop >= ((100 / cfg.wifichancycle) * (cfg.wifiscancycle * 2)) ) {
|
||||
u8x8.setPowerSave(!cfg.screenon); // set display on if enabled
|
||||
nloop = 0; // reset wlan sniffing loop counter
|
||||
|
||||
// execute BLE count if BLE function is enabled
|
||||
#ifdef BLECOUNTER
|
||||
if ( cfg.blescan )
|
||||
BLECount();
|
||||
#endif
|
||||
|
||||
// Prepare and execute LoRaWAN data upload
|
||||
u8x8.setCursor(0,4);
|
||||
u8x8.printf("MAC#: %4i", macnum);
|
||||
do_send(&sendjob); // send payload
|
||||
vTaskDelay(500/portTICK_PERIOD_MS);
|
||||
yield();
|
||||
|
||||
// clear counter if not in cumulative counter mode
|
||||
if ( cfg.countermode != 1 ) {
|
||||
macs.erase(macs.begin(), macs.end()); // clear RAM
|
||||
macnum = 0;
|
||||
u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter
|
||||
}
|
||||
|
||||
// wait until payload is sent, while wifi scanning and mac counting task continues
|
||||
lorawait = 0;
|
||||
while(LMIC.opmode & OP_TXRXPEND) {
|
||||
if(!lorawait) u8x8.drawString(0,6,"LoRa wait ");
|
||||
lorawait++;
|
||||
// in case sending really fails: reset and rejoin network
|
||||
if( (lorawait % MAXLORARETRY ) == 0) {
|
||||
ESP_LOGI(TAG, "Payload not sent, trying reset and rejoin");
|
||||
esp_restart();
|
||||
};
|
||||
vTaskDelay(1000/portTICK_PERIOD_MS);
|
||||
yield();
|
||||
}
|
||||
|
||||
u8x8.clearLine(6);
|
||||
|
||||
if (cfg.screenon && cfg.screensaver) vTaskDelay(2000/portTICK_PERIOD_MS); // pause for displaying results
|
||||
yield();
|
||||
u8x8.setPowerSave(1 && cfg.screensaver); // set display off if screensaver is enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end wifi specific parts ------------------------------------------------------------ */
|
||||
|
||||
// uptime counter 64bit to prevent millis() rollover after 49 days
|
||||
uint64_t uptime() {
|
||||
static uint32_t low32, high32;
|
||||
uint32_t new_low32 = millis();
|
||||
if (new_low32 < low32) high32++;
|
||||
low32 = new_low32;
|
||||
return (uint64_t) high32 << 32 | low32;
|
||||
}
|
||||
|
||||
// Print a key on display
|
||||
void DisplayKey(const uint8_t * key, uint8_t len, bool lsb) {
|
||||
uint8_t start=lsb?len:0;
|
||||
uint8_t end = lsb?0:len;
|
||||
const uint8_t * p ;
|
||||
for (uint8_t i=0; i<len ; i++) {
|
||||
p = lsb ? key+len-i-1 : key+i;
|
||||
u8x8.printf("%02X", *p);
|
||||
}
|
||||
u8x8.printf("\n");
|
||||
}
|
||||
|
||||
void init_display(const char *Productname, const char *Version) {
|
||||
u8x8.begin();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
#ifdef HAS_DISPLAY
|
||||
uint8_t buf[32];
|
||||
u8x8.clear();
|
||||
u8x8.setFlipMode(0);
|
||||
u8x8.setInverseFont(1);
|
||||
u8x8.draw2x2String(0, 0, Productname);
|
||||
u8x8.setInverseFont(0);
|
||||
u8x8.draw2x2String(2, 2, Productname);
|
||||
delay(1500);
|
||||
u8x8.clear();
|
||||
u8x8.setFlipMode(1);
|
||||
u8x8.setInverseFont(1);
|
||||
u8x8.draw2x2String(0, 0, Productname);
|
||||
u8x8.setInverseFont(0);
|
||||
u8x8.draw2x2String(2, 2, Productname);
|
||||
delay(1500);
|
||||
|
||||
u8x8.setFlipMode(0);
|
||||
u8x8.clear();
|
||||
|
||||
// Display chip information
|
||||
#ifdef VERBOSE
|
||||
esp_chip_info_t chip_info;
|
||||
esp_chip_info(&chip_info);
|
||||
u8x8.printf("ESP32 %d cores\nWiFi%s%s\n",
|
||||
chip_info.cores,
|
||||
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
||||
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
|
||||
u8x8.printf("ESP Rev.%d\n", chip_info.revision);
|
||||
u8x8.printf("%dMB %s Flash\n", spi_flash_get_chip_size() / (1024 * 1024),
|
||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext.");
|
||||
#endif // VERBOSE
|
||||
|
||||
u8x8.print(Productname);
|
||||
u8x8.print(" v");
|
||||
u8x8.println(PROGVERSION);
|
||||
u8x8.println("DEVEUI:");
|
||||
os_getDevEui((u1_t*) buf);
|
||||
DisplayKey(buf, 8, true);
|
||||
delay(5000);
|
||||
u8x8.clear();
|
||||
#endif // HAS_DISPLAY
|
||||
}
|
||||
|
||||
/* begin Aruino SETUP ------------------------------------------------------------ */
|
||||
|
||||
void setup() {
|
||||
|
||||
// setup debug output or silence device
|
||||
#ifdef VERBOSE
|
||||
Serial.begin(115200);
|
||||
esp_log_level_set("*", ESP_LOG_VERBOSE);
|
||||
#else
|
||||
// mute logs completely by redirecting them to silence function
|
||||
esp_log_level_set("*", ESP_LOG_NONE);
|
||||
esp_log_set_vprintf(redirect_log);
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Starting %s %s", PROGNAME, PROGVERSION);
|
||||
|
||||
// ESP Event Loop
|
||||
esp_event_loop_init(NULL, NULL);
|
||||
|
||||
// Print chip information on startup
|
||||
#ifdef VERBOSE
|
||||
esp_chip_info_t chip_info;
|
||||
esp_chip_info(&chip_info);
|
||||
ESP_LOGI(TAG, "This is ESP32 chip with %d CPU cores, WiFi%s%s, silicon revision %d, %dMB %s Flash",
|
||||
chip_info.cores,
|
||||
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
||||
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
|
||||
chip_info.revision, spi_flash_get_chip_size() / (1024 * 1024),
|
||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
|
||||
#endif // VERBOSE
|
||||
|
||||
// Read settings from NVRAM
|
||||
loadConfig(); // includes initialize if necessary
|
||||
|
||||
// initialize hardware -> perhaps to be moved to new hal.cpp
|
||||
#ifdef HAS_LED
|
||||
// initialize LED
|
||||
pinMode(LED_BUILTIN, OUTPUT); // white LED on Heltec board
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
// install button interrupt
|
||||
pinMode(GPIO_NUM_0, INPUT_PULLDOWN); // button "PROG" on Heltec board
|
||||
attachInterrupt(digitalPinToInterrupt(GPIO_NUM_0), isr_button_pressed, FALLING);
|
||||
#endif
|
||||
|
||||
// initialize wifi antenna
|
||||
#ifdef LOPY
|
||||
antenna_init();
|
||||
antenna_select(WIFI_LOPY_ANTENNA);
|
||||
#endif
|
||||
|
||||
// initialize display
|
||||
init_display(PROGNAME, PROGVERSION);
|
||||
u8x8.setPowerSave(!cfg.screenon); // set display off if disabled
|
||||
u8x8.setCursor(0,5);
|
||||
u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: %4i", cfg.rssilimit);
|
||||
u8x8.drawString(0,6,"Join Wait ");
|
||||
|
||||
// output LoRaWAN keys to console
|
||||
#ifdef VERBOSE
|
||||
printKeys();
|
||||
#endif // VERBOSE
|
||||
|
||||
os_init(); // setup LMIC
|
||||
os_setCallback(&initjob, lora_init); // setup initial job & join network
|
||||
wifi_sniffer_init(); // setup wifi in monitor mode and start MAC counting
|
||||
|
||||
// Start FreeRTOS tasks
|
||||
#if CONFIG_FREERTOS_UNICORE // run all tasks on core 0 and switch off core 1
|
||||
ESP_LOGI(TAG, "Starting Lora task on core 0");
|
||||
xTaskCreatePinnedToCore(lorawan_loop, "loratask", 2048, ( void * ) 1, ( 5 | portPRIVILEGE_BIT ), NULL, 0);
|
||||
ESP_LOGI(TAG, "Starting Wifi task on core 0");
|
||||
xTaskCreatePinnedToCore(wifi_sniffer_loop, "wifisniffer", 4096, ( void * ) 1, 1, NULL, 0);
|
||||
// to come here: code for switching off core 1
|
||||
#else // run wifi task on core 0 and lora task on core 1
|
||||
ESP_LOGI(TAG, "Starting Lora task on core 1");
|
||||
xTaskCreatePinnedToCore(lorawan_loop, "loratask", 2048, ( void * ) 1, ( 5 | portPRIVILEGE_BIT ), NULL, 1);
|
||||
ESP_LOGI(TAG, "Starting Wifi task on core 0");
|
||||
xTaskCreatePinnedToCore(wifi_sniffer_loop, "wifisniffer", 4096, ( void * ) 1, 1, NULL, 0);
|
||||
#endif
|
||||
|
||||
// Kickoff first sendjob, use payload "0000"
|
||||
uint8_t mydata[] = "0000";
|
||||
do_send(&sendjob);
|
||||
}
|
||||
|
||||
/* end Aruino SETUP ------------------------------------------------------------ */
|
||||
|
||||
|
||||
/* begin Aruino LOOP ------------------------------------------------------------ */
|
||||
|
||||
// Arduino main moop, runs on core 1
|
||||
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
|
||||
void loop() {
|
||||
while(1) {
|
||||
|
||||
if (ButtonTriggered) {
|
||||
ButtonTriggered = false;
|
||||
ESP_LOGI(TAG, "Button pressed, resetting device to factory defaults");
|
||||
eraseConfig();
|
||||
esp_restart();
|
||||
}
|
||||
else {
|
||||
vTaskDelay(1000/portTICK_PERIOD_MS);
|
||||
uptimecounter = uptime() / 1000; // count uptime seconds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end Aruino LOOP ------------------------------------------------------------ */
|
104
src/main.h
Normal file
104
src/main.h
Normal file
@ -0,0 +1,104 @@
|
||||
// program version
|
||||
#define PROGVERSION "1.2.0" // use max 10 chars here!
|
||||
#define PROGNAME "PAXCNT"
|
||||
|
||||
// Verbose enables serial output
|
||||
#define VERBOSE 1 // comment out to silence the device, for mute use build option
|
||||
|
||||
// set this to include BLE counting and vendor filter functions
|
||||
#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
|
||||
|
||||
// BLE scan time
|
||||
#define BLESCANTIME 30 // [seconds]
|
||||
|
||||
// WiFi Sniffer cycle interval
|
||||
#define SEND_SECS 120 // [seconds/2] -> 240 sec.
|
||||
|
||||
// WiFi sniffer config
|
||||
#define WIFI_CHANNEL_MAX 13
|
||||
#define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec.
|
||||
|
||||
// Default LoRa Spreadfactor
|
||||
#define LORASFDEFAULT 9 // 7 ... 12
|
||||
#define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy
|
||||
#define RCMDPORT 2 // LoRaWAN Port on which device listenes for remote commands
|
||||
|
||||
// LMIC settings
|
||||
// define hardware independent LMIC settings here, settings of standard library in /lmic/config.h will be ignored
|
||||
// define hardware specifics settings in platformio.ini as build_flag for hardware environment
|
||||
|
||||
#define CFG_eu868 1
|
||||
//#define CFG_us915 1
|
||||
// This is the SX1272/SX1273 radio, which is also used on the HopeRF
|
||||
// RFM92 boards.
|
||||
//#define CFG_sx1272_radio 1
|
||||
// This is the SX1276/SX1277/SX1278/SX1279 radio, which is also used on
|
||||
// the HopeRF RFM95 boards.
|
||||
//#define CFG_sx1276_radio 1
|
||||
|
||||
// 16 μs per tick
|
||||
// LMIC requires ticks to be 15.5μs - 100 μs long
|
||||
#define US_PER_OSTICK_EXPONENT 4
|
||||
#define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT)
|
||||
#define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK)
|
||||
|
||||
// Set this to 1 to enable some basic debug output (using printf) about
|
||||
// RF settings used during transmission and reception. Set to 2 to
|
||||
// enable more verbose output. Make sure that printf is actually
|
||||
// configured (e.g. on AVR it is not by default), otherwise using it can
|
||||
// cause crashing.
|
||||
//#define LMIC_DEBUG_LEVEL 1
|
||||
|
||||
// Enable this to allow using printf() to print to the given serial port
|
||||
// (or any other Print object). This can be easy for debugging. The
|
||||
// current implementation only works on AVR, though.
|
||||
//#define LMIC_PRINTF_TO Serial
|
||||
|
||||
// Any runtime assertion failures are printed to this serial port (or
|
||||
// any other Print object). If this is unset, any failures just silently
|
||||
// halt execution.
|
||||
#define LMIC_FAILURE_TO Serial
|
||||
|
||||
// Uncomment this to disable all code related to joining
|
||||
//#define DISABLE_JOIN
|
||||
// Uncomment this to disable all code related to ping
|
||||
#define DISABLE_PING
|
||||
// Uncomment this to disable all code related to beacon tracking.
|
||||
// Requires ping to be disabled too
|
||||
#define DISABLE_BEACONS
|
||||
|
||||
// Uncomment these to disable the corresponding MAC commands.
|
||||
// Class A
|
||||
//#define DISABLE_MCMD_DCAP_REQ // duty cycle cap
|
||||
//#define DISABLE_MCMD_DN2P_SET // 2nd DN window param
|
||||
//#define DISABLE_MCMD_SNCH_REQ // set new channel
|
||||
// Class B
|
||||
//#define DISABLE_MCMD_PING_SET // set ping freq, automatically disabled by DISABLE_PING
|
||||
//#define DISABLE_MCMD_BCNI_ANS // next beacon start, automatical disabled by DISABLE_BEACON
|
||||
|
||||
// In LoRaWAN, a gateway applies I/Q inversion on TX, and nodes do the
|
||||
// same on RX. This ensures that gateways can talk to nodes and vice
|
||||
// versa, but gateways will not hear other gateways and nodes will not
|
||||
// hear other nodes. By uncommenting this macro, this inversion is
|
||||
// disabled and this node can hear other nodes. If two nodes both have
|
||||
// this macro set, they can talk to each other (but they can no longer
|
||||
// hear gateways). This should probably only be used when debugging
|
||||
// and/or when talking to the radio directly (e.g. like in the "raw"
|
||||
// example).
|
||||
//#define DISABLE_INVERT_IQ_ON_RX
|
||||
|
||||
// This allows choosing between multiple included AES implementations.
|
||||
// Make sure exactly one of these is uncommented.
|
||||
//
|
||||
// This selects the original AES implementation included LMIC. This
|
||||
// implementation is optimized for speed on 32-bit processors using
|
||||
// fairly big lookup tables, but it takes up big amounts of flash on the
|
||||
// AVR architecture.
|
||||
// #define USE_ORIGINAL_AES
|
||||
//
|
||||
// This selects the AES implementation written by Ideetroon for their
|
||||
// own LoRaWAN library. It also uses lookup tables, but smaller
|
||||
// byte-oriented ones, making it use a lot less flash space (but it is
|
||||
// also about twice as slow as the original).
|
||||
#define USE_IDEETRON_AES
|
214
src/rcommand.cpp
Normal file
214
src/rcommand.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
// remote command interpreter
|
||||
// parses multiple number of command / value pairs from LoRaWAN remote command port (RCMDPORT)
|
||||
// checks commands and executes each command with 1 argument per command
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char *TAG = "rcommand";
|
||||
|
||||
// functions defined in configmanager.cpp
|
||||
void eraseConfig(void);
|
||||
void saveConfig(void);
|
||||
|
||||
// table of remote commands and assigned functions
|
||||
typedef struct {
|
||||
const int nam;
|
||||
void (*func)(int);
|
||||
const bool store;
|
||||
} cmd_t;
|
||||
|
||||
// help function to assign LoRa datarates to spreadfactor values
|
||||
void switch_lora (int sf, int tx) {
|
||||
if ( tx > 20 ) return;
|
||||
cfg.txpower = tx;
|
||||
switch (sf) {
|
||||
case 7: LMIC_setDrTxpow(DR_SF7,tx); cfg.lorasf=sf; 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: LMIC_setDrTxpow(DR_SF11,tx); cfg.lorasf=sf; break;
|
||||
case 12: LMIC_setDrTxpow(DR_SF12,tx); cfg.lorasf=sf; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// set of functions that can be triggered by remote commands
|
||||
void set_reset(int val) {
|
||||
switch (val) {
|
||||
case 0: // restart device
|
||||
ESP_LOGI(TAG, "Remote command: restart device");
|
||||
u8x8.clearLine(5);
|
||||
u8x8.setCursor(0, 5);
|
||||
u8x8.printf("Reset pending ");
|
||||
vTaskDelay(10000/portTICK_PERIOD_MS); // wait for LMIC to confirm LoRa downlink to server
|
||||
esp_restart();
|
||||
break;
|
||||
case 1: // reset MAC counter
|
||||
ESP_LOGI(TAG, "Remote command: reset MAC counter");
|
||||
macs.erase(macs.begin(), macs.end()); // clear RAM
|
||||
macnum = 0;
|
||||
u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter
|
||||
u8x8.clearLine(5);
|
||||
u8x8.setCursor(0, 5);
|
||||
u8x8.printf("Reset counter ");
|
||||
break;
|
||||
case 2: // reset device to factory settings
|
||||
ESP_LOGI(TAG, "Remote command: reset device to factory settings");
|
||||
u8x8.clearLine(5);
|
||||
u8x8.setCursor(0, 5);
|
||||
u8x8.printf("Factory reset ");
|
||||
eraseConfig();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
void set_rssi(int val) {
|
||||
cfg.rssilimit = val * -1;
|
||||
ESP_LOGI(TAG, "Remote command: set RSSI limit to %i", cfg.rssilimit);
|
||||
u8x8.clearLine(5);
|
||||
u8x8.setCursor(0, 5);
|
||||
u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: -%4i", cfg.rssilimit);
|
||||
};
|
||||
|
||||
void set_wifiscancycle(int val) {
|
||||
cfg.wifiscancycle = val;
|
||||
ESP_LOGI(TAG, "Remote command: set Wifi scan cycle duration to %i seconds", cfg.wifiscancycle*2);
|
||||
};
|
||||
|
||||
void set_wifichancycle(int val) {
|
||||
cfg.wifichancycle = val;
|
||||
ESP_LOGI(TAG, "Remote command: set Wifi channel switch interval to %i seconds", cfg.wifichancycle/100);
|
||||
};
|
||||
|
||||
void set_blescancycle(int val) {
|
||||
cfg.blescancycle = val;
|
||||
ESP_LOGI(TAG, "Remote command: set Wifi channel cycle duration to %i seconds", cfg.blescancycle);
|
||||
};
|
||||
|
||||
void set_countmode(int val) {
|
||||
switch (val) {
|
||||
case 0: // cyclic unconfirmed
|
||||
cfg.countermode = 0;
|
||||
ESP_LOGI(TAG, "Remote command: set counter mode to cyclic unconfirmed");
|
||||
break;
|
||||
case 1: // cumulative
|
||||
cfg.countermode = 1;
|
||||
ESP_LOGI(TAG, "Remote command: set counter mode to cumulative");
|
||||
break;
|
||||
default: // cyclic confirmed
|
||||
cfg.countermode = 2;
|
||||
ESP_LOGI(TAG, "Remote command: set counter mode to cyclic confirmed");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
void set_screensaver(int val) {
|
||||
ESP_LOGI(TAG, "Remote command: set screen saver to %s ", val ? "on" : "off");
|
||||
switch (val) {
|
||||
case 1: cfg.screensaver = val; break;
|
||||
default: cfg.screensaver = 0; break;
|
||||
}
|
||||
u8x8.setPowerSave(cfg.screensaver); // set display 0=on / 1=off
|
||||
};
|
||||
|
||||
void set_display(int val) {
|
||||
ESP_LOGI(TAG, "Remote command: set screen to %s", val ? "on" : "off");
|
||||
switch (val) {
|
||||
case 1: cfg.screenon = val; break;
|
||||
default: cfg.screenon = 0; break;
|
||||
}
|
||||
u8x8.setPowerSave(!cfg.screenon); // set display 0=on / 1=off
|
||||
};
|
||||
|
||||
void set_lorasf(int val) {
|
||||
ESP_LOGI(TAG, "Remote command: set LoRa SF to %i", val);
|
||||
switch_lora(val, cfg.txpower);
|
||||
};
|
||||
|
||||
void set_loraadr(int val) {
|
||||
ESP_LOGI(TAG, "Remote command: set LoRa ADR mode to %s", val ? "on" : "off");
|
||||
switch (val) {
|
||||
case 1: cfg.adrmode = val; break;
|
||||
default: cfg.adrmode = 0; break;
|
||||
}
|
||||
LMIC_setAdrMode(cfg.adrmode);
|
||||
};
|
||||
|
||||
void set_blescan(int val) {
|
||||
ESP_LOGI(TAG, "Remote command: set BLE scan mode to %s", val ? "on" : "off");
|
||||
switch (val) {
|
||||
case 1: cfg.blescan = val; break;
|
||||
default:
|
||||
cfg.blescan = 0;
|
||||
btStop();
|
||||
u8x8.clearLine(3); // clear BLE results from display
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
void set_lorapower(int val) {
|
||||
ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %i", val);
|
||||
switch_lora(cfg.lorasf, val);
|
||||
};
|
||||
|
||||
void set_noop (int val) {
|
||||
ESP_LOGI(TAG, "Remote command: noop - doing nothing");
|
||||
};
|
||||
|
||||
void get_config (int val) {
|
||||
ESP_LOGI(TAG, "Remote command: get configuration");
|
||||
int size = sizeof(configData_t);
|
||||
// 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, "Configuration data queued in send queue");
|
||||
};
|
||||
|
||||
void get_uptime (int val) {
|
||||
ESP_LOGI(TAG, "Remote command: get uptime");
|
||||
int size = 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, "Uptime queued in send queue");
|
||||
};
|
||||
|
||||
// assign previously defined functions to set of numeric remote commands
|
||||
// format: opcode, function, flag (1 = do make settings persistent / 0 = don't)
|
||||
//
|
||||
cmd_t table[] = {
|
||||
{0x01, set_rssi, true},
|
||||
{0x02, set_countmode, true},
|
||||
{0x03, set_screensaver, true},
|
||||
{0x04, set_display, true},
|
||||
{0x05, set_lorasf, true},
|
||||
{0x06, set_lorapower, true},
|
||||
{0x07, set_loraadr, true},
|
||||
{0x08, set_noop, false},
|
||||
{0x09, set_reset, false},
|
||||
{0x0a, set_wifiscancycle, true},
|
||||
{0x0b, set_wifichancycle, true},
|
||||
{0x0c, set_blescancycle, true},
|
||||
{0x0d, set_blescan, true},
|
||||
{0x80, get_config, false},
|
||||
{0x81, get_uptime, false},
|
||||
};
|
||||
|
||||
// check and execute remote command
|
||||
void rcommand(int cmd, int arg) {
|
||||
int i = sizeof(table) / sizeof(table[0]); // number of commands in command table
|
||||
bool store_flag = false;
|
||||
while(i--) {
|
||||
if(cmd == table[i].nam) { // check if valid command
|
||||
table[i].func(arg); // then execute assigned function
|
||||
if ( table[i].store ) store_flag = true; // set save flag if function needs to store configuration
|
||||
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
|
||||
}
|
1435
src/vendor_array.h
Normal file
1435
src/vendor_array.h
Normal file
File diff suppressed because it is too large
Load Diff
100
src/wifisniffer.cpp
Normal file
100
src/wifisniffer.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include "main.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Basic Config
|
||||
#include "globals.h"
|
||||
#include "loraconf.h"
|
||||
|
||||
// WiFi Functions
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_wifi_types.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_event_loop.h>
|
||||
|
||||
// Local logging tag
|
||||
static const char *TAG = "wifisniffer";
|
||||
|
||||
static wifi_country_t wifi_country = {.cc="EU", .schan=1, .nchan=13, .policy=WIFI_COUNTRY_POLICY_AUTO};
|
||||
|
||||
#ifdef VENDORFILTER
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include "vendor_array.h"
|
||||
#endif
|
||||
|
||||
extern void wifi_sniffer_init(void);
|
||||
extern void wifi_sniffer_set_channel(uint8_t channel);
|
||||
extern void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
||||
|
||||
typedef struct {
|
||||
unsigned frame_ctrl:16;
|
||||
unsigned duration_id:16;
|
||||
uint8_t addr1[6]; /* receiver address */
|
||||
uint8_t addr2[6]; /* sender address */
|
||||
uint8_t addr3[6]; /* filtering address */
|
||||
unsigned sequence_ctrl:16;
|
||||
uint8_t addr4[6]; /* optional */
|
||||
} wifi_ieee80211_mac_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
wifi_ieee80211_mac_hdr_t hdr;
|
||||
uint8_t payload[0]; /* network data ended with 4 bytes csum (CRC32) */
|
||||
} wifi_ieee80211_packet_t;
|
||||
|
||||
void wifi_sniffer_init(void) {
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_country(&wifi_country) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_NULL) );
|
||||
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_max_tx_power(-128) ); // we don't need to TX, so we use lowest power level to save energy
|
||||
wifi_promiscuous_filter_t filter = {.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames
|
||||
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(true));
|
||||
}
|
||||
|
||||
void wifi_sniffer_set_channel(uint8_t channel) {
|
||||
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
|
||||
}
|
||||
|
||||
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_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)ppkt->payload;
|
||||
const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr;
|
||||
char counter [10];
|
||||
|
||||
if (( cfg.rssilimit == 0 ) || (ppkt->rx_ctrl.rssi > cfg.rssilimit )) { // rssi is negative value
|
||||
uint64_t addr2int = ( (uint64_t)hdr->addr2[0] ) | ( (uint64_t)hdr->addr2[1] << 8 ) | ( (uint64_t)hdr->addr2[2] << 16 ) | \
|
||||
( (uint64_t)hdr->addr2[3] << 24 ) | ( (uint64_t)hdr->addr2[4] << 32 ) | ( (uint64_t)hdr->addr2[5] << 40 );
|
||||
|
||||
#ifdef VENDORFILTER
|
||||
uint32_t vendor2int = ( (uint32_t)hdr->addr2[2] ) | ( (uint32_t)hdr->addr2[1] << 8 ) | ( (uint32_t)hdr->addr2[0] << 16 );
|
||||
|
||||
if ( std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end() ) {
|
||||
#endif
|
||||
macs.insert(addr2int);
|
||||
|
||||
// INFO: RSSI when adding MAC
|
||||
ESP_LOGI(TAG, "WiFi RSSI: %02d", ppkt->rx_ctrl.rssi);
|
||||
|
||||
// if new unique MAC logged increment counter on display
|
||||
if ( macs.size() > macnum ) {
|
||||
macnum = macs.size();
|
||||
itoa(macnum, counter, 10);
|
||||
u8x8.draw2x2String(0, 0, counter);
|
||||
ESP_LOGI(TAG, "MAC counter: %4i", macnum);
|
||||
}
|
||||
|
||||
|
||||
#ifdef VENDORFILTER
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Ignoring RSSI %02d (limit: %i)", ppkt->rx_ctrl.rssi, cfg.rssilimit );
|
||||
}
|
||||
yield();
|
||||
}
|
Loading…
Reference in New Issue
Block a user