This commit is contained in:
Oliver Brandmueller 2018-10-25 17:22:21 +02:00
commit 8f740292d9
111 changed files with 11678 additions and 6666 deletions

39
LICENSE
View File

@ -20,9 +20,9 @@ Parts of the source files in this repository are made available under different
listed below. Refer to each individual source file for more details.
------------------------------------------------------------------------------------------------
wifiscan.cpp
wifiscan.cpp and macsniff.cpp:
Prior art was used for wifiscan.cpp and taken from
Parts were derived or taken from
* Copyright (c) 2017, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
* ESP32/016 WiFi Sniffer
@ -208,10 +208,9 @@ under this License:
END OF TERMS AND CONDITIONS"
------------------------------------------------------------------------------------------------
src/lorawan.cpp and /lib/arduino-lmic-1.5.0-<...>
lorawan.cpp
Parts of lorawan.cpp, and the arduino lmic library, which is included in the /lib directory of this
repository, were derived or taken from
Parts of lorawan.cpp, and the arduino lmic library were derived or taken from
Arduino-LMIC Library
TTN OTAA Example
@ -220,12 +219,34 @@ https://github.com/matthijskooijman/arduino-lmic/blob/master/examples/ttn-otaa/
and it's fork
LoraWAN-in-C library, adapted to run under the Arduino environment
https://github.com/jpmeijers/arduino-lmic
https://github.com/mcci-catena/arduino-lmic
under this Licence:
under this MIT Licence:
"MIT License
Copyright (C) 2014-2016 IBM Corporation
Copyright (c) 2016-2018 MCCI Corporation
Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE."
"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."
------------------------------------------------------------------------------------------------
blescan.cpp

View File

@ -53,13 +53,15 @@ Hardware dependent settings (pinout etc.) are stored in board files in /hal dire
<b>3D printable cases</b> can be found (and, if wanted so, ordered) on Thingiverse, see
<A HREF="https://www.thingiverse.com/thing:2670713">Heltec</A>, <A HREF="https://www.thingiverse.com/thing:2811127">TTGOv2</A>, <A HREF="https://www.thingiverse.com/thing:3005574">TTGOv2.1</A>, <A HREF="https://www.thingiverse.com/thing:3041339">T-BEAM</A> for example.<br>
<b>Power consumption</b> was metered at around 750 - 1000mW, depending on board and user settings in paxcounter.conf. If you are limited on battery, you may want to save around 30% power by disabling bluetooth (commenting out line *#define BLECOUNTER* in paxcounter.conf).
<b>Power consumption</b> was metered at around 450 - 1000mW, depending on board and user settings in paxcounter.conf. If you are limited on battery, you may want to save around 30% power by disabling bluetooth (commenting out line *#define BLECOUNTER* in paxcounter.conf).
# Preparing
Before compiling the code,
- **edit paxcounter.conf** and tailor settings in this file according to your needs and use case. Please take care of the duty cycle regulations of the LoRaWAN network you're going to use.
- **edit src/paxcounter.conf** and tailor settings in this file according to your needs and use case. Please take care of the duty cycle regulations of the LoRaWAN network you're going to use.
- **edit src/lmic_config.h** and tailor settings in this file according to your country and device hardware. Please take care of national regulations when selecting the frequency band for LoRaWAN.
- **create file loraconf.h in your local /src directory** using the template [loraconf.sample.h](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/loraconf.sample.h) and populate it with your personal APPEUI und APPKEY for the LoRaWAN network. If you're using popular <A HREF="https://thethingsnetwork.org">TheThingsNetwork</A> you can copy&paste the keys from TTN console or output of ttnctl.
@ -100,7 +102,7 @@ Note: If you use this software you do this at your own risk. That means that you
# Privacy disclosure
Paxcounter generates identifiers for sniffed MAC adresses and collects them temporary in the device's RAM for a configurable scan cycle time (default 240 seconds). After each scan cycle the collected identifiers are cleared. Identifiers are generated by salting and hashing MAC adresses. The random salt value changes after each scan cycle. Identifiers and MAC adresses are never transferred to the LoRaWAN network. No persistent storing of MAC adresses, identifiers or timestamps and no other kind of analytics than counting are implemented in this code. Wireless networks are not touched by this code, but MAC adresses from wireless devices as well within as not within wireless networks, regardless if encrypted or unencrypted, are sniffed and processed by this code. If the bluetooth option in the code is enabled, bluetooth MACs are scanned and processed by the included BLE stack, then hashed and counted by this code.
Paxcounter generates identifiers for sniffed MAC adresses and collects them temporary in the device's RAM for a configurable scan cycle time (default 60 seconds). After each scan cycle the collected identifiers are cleared. Identifiers are generated by salting and hashing MAC adresses. The random salt value changes after each scan cycle. Identifiers and MAC adresses are never transferred to the LoRaWAN network. No persistent storing of MAC adresses, identifiers or timestamps and no other kind of analytics than counting are implemented in this code. Wireless networks are not touched by this code, but MAC adresses from wireless devices as well within as not within wireless networks, regardless if encrypted or unencrypted, are sniffed and processed by this code. If the bluetooth option in the code is enabled, bluetooth MACs are scanned and processed by the included BLE stack, then hashed and counted by this code.
# LED blink pattern
@ -336,3 +338,4 @@ Thanks to
- [Oliver Brandmüller](https://github.com/spmrider) for idea and initial setup of this project
- [Charles Hallard](https://github.com/hallard) for major code contributions to this project
- [robbi5](https://github.com/robbi5) for the payload converter
- [terrillmoore](https://github.com/mcci-catena) for maintaining the LMIC for arduino LoRaWAN stack

View File

@ -53,7 +53,7 @@ extern std::array<uint64_t, 0xff> beacons;
extern TaskHandle_t irqHandlerTask, wifiSwitchTask;
#ifdef HAS_GPS
#include "gps.h"
#include "gpsread.h"
#endif
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
@ -67,7 +67,7 @@ extern TaskHandle_t irqHandlerTask, wifiSwitchTask;
#endif
#ifdef HAS_SPI
#include "spi.h"
#include "spisend.h"
#endif
#ifdef HAS_DISPLAY

View File

@ -1,10 +1,10 @@
#ifndef _GPS_H
#define _GPS_H
#ifndef _GPSREAD_H
#define _GPSREAD_H
#include <TinyGPS++.h> // library for parsing NMEA data
#include <TimeLib.h>
#ifdef GPS_QUECTEL_L76 // Needed for reading from I2C Bus
#ifdef GPS_I2C // Needed for reading from I2C Bus
#include <Wire.h>
#endif

View File

@ -17,7 +17,7 @@ int version_compare(const String v1, const String v2);
void display(const uint8_t row, const std::string status,
const std::string msg);
#ifdef HAS_DISPLAY
void show_progress(size_t current, size_t size);
void show_progress(unsigned long current, unsigned long size);
#endif
#endif // USE_OTA

View File

@ -16,5 +16,6 @@ typedef struct {
} cmd_t;
void rcommand(uint8_t cmd[], uint8_t cmdlength);
void do_reset();
#endif

39
include/readme.txt Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@ -1,5 +1,5 @@
#ifndef _SPI_H
#define _SPI_H
#ifndef _SPISEND_H
#define _SPISEND_H
extern TaskHandle_t SpiTask;
extern QueueHandle_t SPISendQueue;

View File

@ -1,365 +0,0 @@
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.

View File

@ -1,9 +0,0 @@
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=*

View File

@ -1,41 +0,0 @@
/*******************************************************************************
* 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_

View File

@ -1,91 +0,0 @@
/*******************************************************************************
* 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_

View File

@ -1,391 +0,0 @@
/*******************************************************************************
* 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_

View File

@ -1,129 +0,0 @@
/*******************************************************************************
* 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);
}
}

46
lib/arduino-lmic-master/.gitignore vendored Normal file
View File

@ -0,0 +1,46 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# Backup files
*.BAK
*.CKP
# files from Visual Micro
Release
*.vcxproj
*.vcxproj.filters
*.vcxitems
vs-readme.txt
__vm
.vs
*.sln
# files from vscode
.vscode

View File

@ -0,0 +1,17 @@
^CVS
.*/CVS
.*/CVS/.*
\.\#.*$
^\.DS_Store$
.*\.BAK$
.*\.bak$
.*\.CKP$
^build
^build/.*
^.*\.o$
^.*\.d$
^.*\.td$
\.a$
^core$
.*/core$
.*\.rej$

View File

@ -0,0 +1,73 @@
# Adding a new region to Arduino LMIC
This variant of the Arduino LMIC code supports adding additional regions beyond the eu868 and us915 bands supoprted by the original IBM LMIC 1.6 code.
This document sketches how to add a new region.
## Planning
### Determine the region/region category
Compare the target region (in the LoRaWAN regional specification) to the EU868 and US915 regions. There are three possibilities.
1. the region is like the EU region. There are a limited number of channels (up to 8), and only a small number of channels are used for OTAA join operations. The response masks refer to individual channels, and the JOIN-response can send frequencies of specific channels to be added.
2. The region is like the US region. There are many channels (the US has 64) with fixed frequences, and the channel masks refer to subsets of the fixed channels.
3. The region is not really like either the EU or US. At the moment, it seems that CN470-510MHz (section 2.6 of LoRaWAN Regional Parameters spec V1.0.2rB) falls into this category.
Bandplans in categories (1) and (2) are easily supported. Bandplans in category (3) are not supoprted by the current code.
### Check whether the region is already listed in `lmic_config_preconditions.h`
Check `src/lmic/lmic_config_preconditions.h` and scan the `LMIC_REGION_...` definitions. The numeric values are assigned based on the subchapter in section 2 of the LoRaWAN 1.0.2 Regional Parmaters document. If your symbol is already there, then the first part of adaptation has already been done. There will already be a corresponding `CFG_...` symbol. But if your region isn't supported, you'll need to add it here.
- `LMIC_REGION_myregion` must be a distinct integer, and must be less than 32 (so as to fit into a bitmask)
## Make the appropriate changes in `lmic_config_preconditions.h`
- `LMIC_REGION_SUPPORTED` is a bit mask of all regions supported by the code. Your new region must appear in this list.
- `CFG_LMIC_REGION_MASK` is a bit mask that, when expanded, returns a bitmask for each defined `CFG_...` variable. You must add your `CFG_myregion` symbol to this list.
- `CFG_region` evaluates to the `LMIC_REGION_...` value for the selected region (as long as only one region is selected). The header files check for this, so you don't have to.
- `CFG_LMIC_EU_like_MASK` is a bitmask of regions that are EU-like, and `CFG_LMIC_US_like_MASK` is a bitmask of regions that are US-like. Add your region to the appropriate one of these two variables.
## Document your region in `config.h`
You'll see where the regions are listed. Add yours.
## Document your region in `README.md`
You'll see where the regions are listed. Add yours.
## Add the definitions for your region in `lorabase.h`
- If your region is EU like, copy the EU block. Document any duty-cycle limitations.
- if your region is US like, copy the US block.
- As appropriate, copy `lorabase_eu868.h` or `lorabase_us915.h` to make your own `lorabase_myregion.h`. Fill in the symbols.
At time of writing, you need to duplicate some code to copy some settings from `..._CONFIG_SYMBOL` to the corresponding `CONFIG_SYMBOL`; and you need to put some region-specific knowledge into the `lorabase.h` header file. The long-term direction is to put all the regional knowledge into the region-specific header, and then the central code will just copy. The architectural impulse is that we'll want to be able to reuse the regional header files in other contexts. On the other hand, because it's error prone, we don't want to `#include` files that aren't being used; otherwise you could accidentally use EU parameters in US code, etc.
- Now's a good time to test-compile and clean out errors introduced. You'll still have problems compiling, but they should look like this:
```
lmic.c:29: In file included from
lmic_bandplan.h: 52:3: error: #error "maxFrameLen() not defined by bandplan"
# error "maxFrameLen() not defined by bandplan"
lmic_bandplan.h: 56:3: error: #error "pow2dBm() not defined by bandplan"
# error "pow2dBm() not defined by bandplan"
```
## Edit `lmic_bandplan.h`
The next step is to add the region-specific interfaces for your region.
Do this by editing `lmic_bandplan.h` and adding the appropriate call to a (new) region-specific file `lmic_bandplan_myregion.h`, where "myregion" is the abbreviation for your region.
Then, if your region is eu868-like, copy `lmic_bandplan_eu868.h` to create your new region-specific header file; otherwise copy `lmic_bandplan_us915.h`.
## Create `lmic_myregion.c`
Once again, you will start by copying either `lmic_eu868.c` or `lmic_us915.c` to create your new file. Then touch it up as necessary.
## General Discussion
- You'll find it easier to do the test compiles using the example scripts in this directory, rather than trying to get all the Catena framework going too. On the other hand, working with the Catena framework will expose more problems.
## Addding the region to the Arduino_LoRaWAN library
In `Arduino_LoRaWAN_ttn.h`:
- Add a new class with name `Arduino_LoRaWAN_ttn_myregion`, copied either from the `Arduino_LoRaWAN_ttn_eu868` class or the `Arduino_LoRaWAN_ttn_us915` class.
- Extend the list of `#if defined(CFG_eu868)` etc to define `Arduino_LoRaWAN_REGION_TAG` to the suffix of your new class if `CFG_myregion` is defined.
Then copy either `ttn_eu868_netbegin.cpp`/`ttn_eu868_netjoin.cpp` or `ttn_us915_netbegin.cpp`/`ttn_us915_netjoin.cpp` to make your own file(s) for the key functions.

View File

@ -0,0 +1,23 @@
MIT License
Copyright (C) 2014-2016 IBM Corporation
Copyright (c) 2016-2018 MCCI Corporation
Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -1,3 +1,25 @@
==============================================================================
LMIC VERSION 1.6 (13-July-2015)
---------------------------------
- License changed to BSD
- Modem included, see LMiC-Modem.pdf and examples/modem
- Additional stm32 hardware and Blipper board specific peripheral code
==============================================================================
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
==============================================================================
LMIC VERSION 1.4 (17-Mar-2015)
-------------------------------
@ -14,15 +36,3 @@ LMIC VERSION 1.4 (17-Mar-2015)
- 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
==============================================================================

View File

@ -0,0 +1,9 @@
name=MCCI LoRaWAN LMIC library
version=2.2.2
author=IBM, Matthis Kooijman, Terry Moore, ChaeHee Won, Frank Rose
maintainer=Terry Moore <tmm@mcci.com>
sentence=Arduino port of the LMIC (LoraWAN-MAC-in-C) framework provided by IBM.
paragraph=Supports SX1272/SX1276 and HopeRF RFM92/RFM95 tranceivers. Refactored to support multiple bandplans beyond the original two supported by the IBM LMIC code. Various enhancements and bug fixes from MCCI and The Things Network New York. Original IBM URL http://www.research.ibm.com/labs/zurich/ics/lrsc/lmic.html.
category=Communication
url=https://github.com/mcci-catena/arduino-lmic
architectures=*

View File

@ -72,7 +72,14 @@ static CONST_TABLE(unsigned char, S_Table)[16][16] = {
{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);
#ifdef __cplusplus
extern "C" {
#endif
void lmic_aes_encrypt(unsigned char *Data, unsigned char *Key);
#ifdef __cplusplus
}
#endif
static void AES_Add_Round_Key(unsigned char *Round_Key);
static unsigned char AES_Sub_Byte(unsigned char Byte);
static void AES_Shift_Rows();

View File

@ -1,13 +1,29 @@
/*******************************************************************************
* 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
/*
* Copyright (c) 2014-2016 IBM Corporation.
* All rights reserved.
*
* Contributors:
* IBM Zurich Research Lab - initial API, implementation and documentation
*******************************************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "../lmic/oslmic.h"

View File

@ -34,9 +34,9 @@
// This should be defined elsewhere
void lmic_aes_encrypt(u1_t *data, u1_t *key);
// global area for passing parameters (aux, key)
// global area for passing parameters (aux, key) and for storing round keys
u4_t AESAUX[16/sizeof(u4_t)];
u4_t AESKEY[16/sizeof(u4_t)];
u4_t AESKEY[11*16/sizeof(u4_t)];
// Shift the given buffer left one bit
static void shift_left(xref2u1_t buf, u1_t len) {

View File

@ -17,59 +17,71 @@
// -----------------------------------------------------------------------------
// I/O
static const lmic_pinmap *plmic_pins;
static void hal_interrupt_init(); // Fwd declaration
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);
ASSERT(plmic_pins->nss != LMIC_UNUSED_PIN);
ASSERT(plmic_pins->dio[0] != LMIC_UNUSED_PIN);
ASSERT(plmic_pins->dio[1] != LMIC_UNUSED_PIN || plmic_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
// Serial.print("nss: "); Serial.println(plmic_pins->nss);
// Serial.print("rst: "); Serial.println(plmic_pins->rst);
// Serial.print("dio[0]: "); Serial.println(plmic_pins->dio[0]);
// Serial.print("dio[1]: "); Serial.println(plmic_pins->dio[1]);
// Serial.print("dio[2]: "); Serial.println(plmic_pins->dio[2]);
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(plmic_pins->nss, OUTPUT);
if (plmic_pins->rxtx != LMIC_UNUSED_PIN)
pinMode(plmic_pins->rxtx, OUTPUT);
if (plmic_pins->rst != LMIC_UNUSED_PIN)
pinMode(plmic_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);
hal_interrupt_init();
}
// val == 1 => tx 1
// val == 1 => tx
void hal_pin_rxtx (u1_t val) {
if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
digitalWrite(lmic_pins.rxtx, val);
if (plmic_pins->rxtx != LMIC_UNUSED_PIN)
digitalWrite(plmic_pins->rxtx, val != plmic_pins->rxtx_rx_active);
}
// set radio RST pin to given value (or keep floating!)
void hal_pin_rst (u1_t val) {
if (lmic_pins.rst == LMIC_UNUSED_PIN)
if (plmic_pins->rst == LMIC_UNUSED_PIN)
return;
if(val == 0 || val == 1) { // drive pin
pinMode(lmic_pins.rst, OUTPUT);
digitalWrite(lmic_pins.rst, val);
pinMode(plmic_pins->rst, OUTPUT);
digitalWrite(plmic_pins->rst, val);
} else { // keep pin floating
pinMode(lmic_pins.rst, INPUT);
pinMode(plmic_pins->rst, INPUT);
}
}
static bool dio_states[NUM_DIO] = {0};
s1_t hal_getRssiCal (void) {
return plmic_pins->rssi_cal;
}
#if !defined(LMIC_USE_INTERRUPTS)
static void hal_interrupt_init() {
pinMode(plmic_pins->dio[0], INPUT);
if (plmic_pins->dio[1] != LMIC_UNUSED_PIN)
pinMode(plmic_pins->dio[1], INPUT);
if (plmic_pins->dio[2] != LMIC_UNUSED_PIN)
pinMode(plmic_pins->dio[2], 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)
if (plmic_pins->dio[i] == LMIC_UNUSED_PIN)
continue;
if (dio_states[i] != digitalRead(lmic_pins.dio[i])) {
if (dio_states[i] != digitalRead(plmic_pins->dio[i])) {
dio_states[i] = !dio_states[i];
if (dio_states[i])
radio_irq_handler(i);
@ -77,33 +89,73 @@ static void hal_io_check() {
}
}
#else
// Interrupt handlers
static ostime_t interrupt_time[NUM_DIO] = {0};
static void hal_isrPin0() {
ostime_t now = os_getTime();
interrupt_time[0] = now ? now : 1;
}
static void hal_isrPin1() {
ostime_t now = os_getTime();
interrupt_time[1] = now ? now : 1;
}
static void hal_isrPin2() {
ostime_t now = os_getTime();
interrupt_time[2] = now ? now : 1;
}
typedef void (*isr_t)();
static isr_t interrupt_fns[NUM_DIO] = {hal_isrPin0, hal_isrPin1, hal_isrPin2};
static void hal_interrupt_init() {
for (uint8_t i = 0; i < NUM_DIO; ++i) {
if (plmic_pins->dio[i] == LMIC_UNUSED_PIN)
continue;
attachInterrupt(digitalPinToInterrupt(plmic_pins->dio[i]), interrupt_fns[i], RISING);
}
}
static void hal_io_check() {
uint8_t i;
for (i = 0; i < NUM_DIO; ++i) {
ostime_t iTime;
if (plmic_pins->dio[i] == LMIC_UNUSED_PIN)
continue;
iTime = interrupt_time[i];
if (iTime) {
interrupt_time[i] = 0;
radio_irq_handler_v2(i, iTime);
}
}
}
#endif // LMIC_USE_INTERRUPTS
// -----------------------------------------------------------------------------
// 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
SPI.begin(plmic_pins->sck, plmic_pins->miso, plmic_pins->mosi, plmic_pins->nss);
}
void hal_pin_nss (u1_t val) {
if (!val)
if (!val) {
uint32_t spi_freq;
if ((spi_freq = plmic_pins->spi_freq) == 0)
spi_freq = LMIC_SPI_FREQ;
SPISettings settings(spi_freq, MSBFIRST, SPI_MODE0);
SPI.beginTransaction(settings);
else
} else {
SPI.endTransaction();
}
//Serial.println(val?">>":"<<");
digitalWrite(lmic_pins.nss, val);
digitalWrite(plmic_pins->nss, val);
}
// perform SPI transaction with radio
@ -224,6 +276,26 @@ void hal_sleep () {
// -----------------------------------------------------------------------------
#if defined(LMIC_PRINTF_TO)
#if !defined(__AVR)
static ssize_t uart_putchar (void *, const char *buf, size_t len) {
return LMIC_PRINTF_TO.write((const uint8_t *)buf, len);
}
static cookie_io_functions_t functions =
{
.read = NULL,
.write = uart_putchar,
.seek = NULL,
.close = NULL
};
void hal_printf_init() {
stdout = fopencookie(NULL, "w", functions);
if (stdout != nullptr) {
setvbuf(stdout, NULL, _IONBF, 0);
}
}
#else // defined(__AVR)
static int uart_putchar (char c, FILE *)
{
LMIC_PRINTF_TO.write(c) ;
@ -241,9 +313,17 @@ void hal_printf_init() {
// The uart is the standard output device STDOUT.
stdout = &uartout ;
}
#endif // !defined(ESP8266) || defined(ESP31B) || defined(ESP32)
#endif // defined(LMIC_PRINTF_TO)
void hal_init () {
void hal_init (void) {
hal_init_ex(&lmic_pins);
}
void hal_init_ex (const void *pContext) {
plmic_pins = (const lmic_pinmap *)pContext;
// configure radio I/O and interrupt handler
hal_io_init();
// configure radio SPI

View File

@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2015-2016 Matthijs Kooijman
* Copyright (c) 2016-2018 MCCI 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
*
* 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;
// be careful of alignment below.
struct lmic_pinmap {
u1_t nss; // byte 0: pin for select
u1_t rxtx; // byte 1: pin for rx/tx control
u1_t rst; // byte 2: pin for reset
u1_t dio[NUM_DIO]; // bytes 3..5: pins for DIO0, DOI1, DIO2
u1_t mosi; // byte 9: pin for master out / slave in (write to LORA chip)
u1_t miso; // byte 10: pin for master in / slave out (read from LORA chip)
u1_t sck; // byte 11: pin for serial clock by master
// true if we must set rxtx for rx_active, false for tx_active
u1_t rxtx_rx_active; // byte 6: polarity of rxtx active
s1_t rssi_cal; // byte 7: cal in dB -- added to RSSI
// measured prior to decision.
// Must include noise guardband!
u4_t spi_freq; // bytes 8..11: SPI freq in Hz.
};
// Use this for any unused pins.
const u1_t LMIC_UNUSED_PIN = 0xff;
// Declared here, to be defined and initialized by the application
// use os_init_ex() if you want not to use a const table.
extern const lmic_pinmap lmic_pins;
#endif // _hal_hal_h_

View File

@ -3,6 +3,8 @@ extern "C"{
#endif
#include "lmic/lmic.h"
#include "lmic/lmic_bandplan.h"
#include "lmic/lmic_util.h"
#ifdef __cplusplus
}

View File

@ -0,0 +1,174 @@
#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 unless you modify the BSP, you have two choices:
//
// - edit {libraries}/arduino-lmic/project_config/lmic_project_config.h;
// - use a BSP like the MCCI Arduino BSPs, which get the configuration
// from the boards.txt file through a menu option.
//
// You definitely should not edit this file.
// set up preconditions, and load configuration if needed.
#ifndef _LMIC_CONFIG_PRECONDITIONS_H_
# include "lmic_config_preconditions.h"
#endif
// check post-conditions.
// make sure that we have exactly one target region defined.
#if CFG_LMIC_REGION_MASK == 0
# define CFG_eu868 1
#elif (CFG_LMIC_REGION_MASK & (-CFG_LMIC_REGION_MASK)) != CFG_LMIC_REGION_MASK
# error You can define at most one of CFG_... variables
#elif (CFG_LMIC_REGION_MASK & LMIC_REGIONS_SUPPORTED) == 0
# error The selected CFG_... region is not supported yet.
#endif
// make sure that LMIC_COUNTRY_CODE is defined.
#ifndef LMIC_COUNTRY_CODE
# define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_NONE
#endif
// if the country code is Japan, then the region must be AS923
#if LMIC_COUNTRY_CODE == LMIC_COUNTRY_CODE_JP && CFG_region != LMIC_REGION_as923
# error "If country code is JP, then region must be AS923"
#endif
// check for internal consistency
#if !(CFG_LMIC_EU_like || CFG_LMIC_US_like)
# error "Internal error: Neither EU-like nor US-like!"
#endif
// 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
// ensure that a radio is defined.
#if ! (defined(CFG_sx1272_radio) || defined(CFG_sx1276_radio))
# warning Target radio not defined, assuming CFG_sx1276_radio
#define CFG_sx1276_radio 1
#elif defined(CFG_sx1272_radio) && defined(CFG_sx1276_radio)
# error You can define at most one of CFG_sx1272_radio and CF_sx1276_radio
#endif
// LMIC requires ticks to be 15.5μs - 100 μs long
#ifndef OSTICKS_PER_SEC
// 16 μs per tick
# ifndef US_PER_OSTICK_EXPONENT
# define US_PER_OSTICK_EXPONENT 4
# endif
# define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT)
# define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK)
#endif /* OSTICKS_PER_SEC */
#if ! (10000 <= OSTICKS_PER_SEC && OSTICKS_PER_SEC < 64516)
# error LMIC requires ticks to be 15.5 us to 100 us long
#endif
// Change the SPI clock speed if you encounter errors
// communicating with the radio.
// The standard range is 125kHz-8MHz, but some boards can go faster.
#ifndef LMIC_SPI_FREQ
#define LMIC_SPI_FREQ 1E6
#endif
// 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.
#ifndef LMIC_DEBUG_LEVEL
#define LMIC_DEBUG_LEVEL 0
#endif
// 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
// Enable this to use interrupt handler routines listening for RISING signals.
// Otherwise, the library polls digital input lines for changes.
//#define LMIC_USE_INTERRUPTS
// If DISABLE_LMIC_FAILURE_TO is defined, runtime assertion failures
// silently halt execution. Otherwise, LMIC_FAILURE_TO should be defined
// as the name of an object derived from Print, which will be used for
// displaying runtime assertion failures. If you say nothing in your
// lmic_project_config.h, runtime assertion failures are displayed
// using the Serial object.
#if ! defined(DISABLE_LMIC_FAILURE_TO) && ! defined(LMIC_FAILURE_TO)
#define LMIC_FAILURE_TO Serial
#endif
// define this in lmic_project_config.h to disable all code related to joining
//#define DISABLE_JOIN
// define this in lmic_project_config.h to disable all code related to ping
//#define DISABLE_PING
// define this in lmic_project_config.h to disable all code related to beacon tracking.
// Requires ping to be disabled too
//#define DISABLE_BEACONS
// define these in lmic_project_config.h 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, automatically 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 defining this macro in lmic_project_config.h,
// 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
#if ! (defined(USE_ORIGINAL_AES) || defined(USE_IDEETRON_AES))
# define USE_IDEETRON_AES
#endif
#if defined(USE_ORIGINAL_AES) && defined(USE_IDEETRON_AES)
# error "You may define at most one of USE_ORIGINAL_AES and USE_IDEETRON_AES"
#endif
// LMIC_DISABLE_DR_LEGACY
// turn off legacy DR_* symbols that vary by bandplan.
// Older code uses these for configuration. EU868_DR_*, US915_DR_*
// etc symbols are prefered, but breaking older code is inconvenient for
// everybody. We don't want to use DR_* in the LMIC itself, so we provide
// this #define to allow them to be removed.
#if !defined(LMIC_DR_LEGACY)
# if !defined(LMIC_DISABLE_DR_LEGACY)
# define LMIC_DR_LEGACY 1
# else // defined(LMIC_DISABLE_DR_LEGACY)
# define LMIC_DR_LEGACY 0
# endif // defined(LMIC_DISABLE_DR_LEGACY)
#endif // LMIC_DR_LEGACY
#endif // _lmic_config_h_

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2016, 2018 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _hal_hpp_
#define _hal_hpp_
#ifdef __cplusplus
extern "C"{
#endif
/*
* initialize hardware (IO, SPI, TIMER, IRQ).
*/
void hal_init (void);
/*
* initialize hardware, passing in platform-specific context
*/
void hal_init_ex (const void *pContext);
/*
* 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);
/*
* get the calibration value for radio_rssi
*/
s1_t hal_getRssiCal (void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // _hal_hpp_

View File

@ -1,13 +1,31 @@
/*******************************************************************************
* 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
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2016 Matthijs Kooijman.
* Copyright (c) 2016-2018 MCCI Corporation.
* All rights reserved.
*
* Contributors:
* IBM Zurich Research Lab - initial API, implementation and documentation
*******************************************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//! @file
//! @brief LMIC API
@ -18,14 +36,91 @@
#include "oslmic.h"
#include "lorabase.h"
#if LMIC_DEBUG_LEVEL > 0 || LMIC_X_DEBUG_LEVEL > 0
# if defined(LMIC_DEBUG_INCLUDE)
# define LMIC_STRINGIFY_(x) #x
# define LMIC_STRINGIFY(x) LMIC_STRINGIFY_(x)
# include LMIC_STRINGIFY(LMIC_DEBUG_INCLUDE)
# endif
# ifdef LMIC_DEBUG_PRINTF_FN
extern void LMIC_DEBUG_PRINTF_FN(const char *f, ...);
# endif // ndef LMIC_DEBUG_PRINTF_FN
#endif
// if LMIC_DEBUG_PRINTF is now defined, just use it. This lets you do anything
// you like with a sufficiently crazy header file.
#if LMIC_DEBUG_LEVEL > 0
# ifndef LMIC_DEBUG_PRINTF
// otherwise, check whether someone configured a print-function to be used,
// and use it if so.
# ifdef LMIC_DEBUG_PRINTF_FN
# define LMIC_DEBUG_PRINTF(f, ...) LMIC_DEBUG_PRINTF_FN(f, ## __VA_ARGS__)
# ifndef LMIC_DEBUG_INCLUDE // If you use LMIC_DEBUG_INCLUDE, put the declaration in there
void LMIC_DEBUG_PRINTF_FN(const char *f, ...);
# endif // ndef LMIC_DEBUG_INCLUDE
# else // ndef LMIC_DEBUG_PRINTF_FN
// if there's no other info, just use printf. In a pure Arduino environment,
// that's what will happen.
# include <stdio.h>
# define LMIC_DEBUG_PRINTF(f, ...) printf(f, ## __VA_ARGS__)
# endif // ndef LMIC_DEBUG_PRINTF_FN
# endif // ndef LMIC_DEBUG_PRINTF
# ifndef LMIC_DEBUG_FLUSH
# ifdef LMIC_DEBUG_FLUSH_FN
# define LMIC_DEBUG_FLUSH() LMIC_DEBUG_FLUSH_FN()
# else // ndef LMIC_DEBUG_FLUSH_FN
// if there's no other info, assume that flush is not needed.
# define LMIC_DEBUG_FLUSH() do { ; } while (0)
# endif // ndef LMIC_DEBUG_FLUSH_FN
# endif // ndef LMIC_DEBUG_FLUSH
#else // LMIC_DEBUG_LEVEL == 0
// If debug level is zero, printf and flush expand to nothing.
# define LMIC_DEBUG_PRINTF(f, ...) do { ; } while (0)
# define LMIC_DEBUG_FLUSH() do { ; } while (0)
#endif // LMIC_DEBUG_LEVEL == 0
//
// LMIC_X_DEBUG_LEVEL enables additional, special print functions for debugging
// RSSI features. This is used sparingly.
#if LMIC_X_DEBUG_LEVEL > 0
# ifdef LMIC_DEBUG_PRINTF_FN
# define LMIC_X_DEBUG_PRINTF(f, ...) LMIC_DEBUG_PRINTF_FN(f, ## __VA_ARGS__)
# else
# error "LMIC_DEBUG_PRINTF_FN must be defined for LMIC_X_DEBUG_LEVEL > 0."
# endif
#else
# define LMIC_X_DEBUG_PRINTF(f, ...) do {;} while(0)
#endif
#ifdef __cplusplus
extern "C"{
#endif
// LMIC version
// LMIC version -- this is ths IBM LMIC version
#define LMIC_VERSION_MAJOR 1
#define LMIC_VERSION_MINOR 5
#define LMIC_VERSION_BUILD 1431528305
#define LMIC_VERSION_MINOR 6
#define LMIC_VERSION_BUILD 1468577746
// Arduino LMIC version
#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \
(((major) << 24u) | ((minor) << 16u) | ((patch) << 8u) | (local))
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(2, 2, 2, 0)
#define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \
(((v) >> 24u) & 0xFFu)
#define ARDUINO_LMIC_VERSION_GET_MINOR(v) \
(((v) >> 16u) & 0xFFu)
#define ARDUINO_LMIC_VERSION_GET_PATCH(v) \
(((v) >> 8u) & 0xFFu)
#define ARDUINO_LMIC_VERSION_GET_LOCAL(v) \
((v) & 0xFFu)
//! Only For Antenna Tuning Tests !
//#define CFG_TxContinuousMode 1
enum { MAX_FRAME_LEN = 64 }; //!< Library cap on max frame length
enum { TXCONF_ATTEMPTS = 8 }; //!< Transmit attempts for confirmed frames
@ -43,7 +138,7 @@ enum { JOIN_GUARD_ms = 9000 }; // msecs - don't start Join Req/Acc transa
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 ====================================================
#if CFG_LMIC_EU_like // EU868 spectrum ====================================================
enum { MAX_CHANNELS = 16 }; //!< Max supported channels
enum { MAX_BANDS = 4 };
@ -58,10 +153,9 @@ struct band_t {
};
TYPEDEF_xref2band_t; //!< \internal
#elif defined(CFG_us915) // US915 spectrum =================================================
#elif CFG_LMIC_US_like // US915 spectrum =================================================
enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable
enum { MAX_TXPOW_125kHz = 30 };
#endif // ==========================================================================
@ -140,7 +234,8 @@ 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 };
EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE, EV_SCAN_FOUND,
EV_TXSTART };
typedef enum _ev_t ev_t;
enum {
@ -152,9 +247,14 @@ struct lmic_t {
// Radio settings TX/RX (also accessed by HAL)
ostime_t txend;
ostime_t rxtime;
// LBT info
ostime_t lbt_ticks; // ticks to listen
s1_t lbt_dbmax; // max permissible dB on our channel (eg -80)
u4_t freq;
s1_t rssi;
s1_t snr;
s1_t snr; // LMIC.snr is SNR times 4
rps_t rps;
u1_t rxsyms;
u1_t dndr;
@ -163,16 +263,17 @@ struct lmic_t {
osjob_t osjob;
// Channel scheduling
#if defined(CFG_eu868)
#if CFG_LMIC_EU_like
band_t bands[MAX_BANDS];
u4_t channelFreq[MAX_CHANNELS];
u2_t channelDrMap[MAX_CHANNELS];
u2_t channelMap;
#elif defined(CFG_us915)
#elif CFG_LMIC_US_like
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
u2_t activeChannels125khz;
u2_t activeChannels500khz;
#endif
u1_t txChnl; // channel for next TX
u1_t globalDutyRate; // max rate: 1/2^k
@ -215,6 +316,7 @@ struct lmic_t {
u1_t margin;
bit_t ladrAns; // link adr adapt answer pending
bit_t devsAns; // device status answer pending
s1_t devAnsMargin; // SNR value between -32 and 31 (inclusive) for the last successfully received DevStatusReq command
u1_t adrEnabled;
u1_t moreData; // NWK has more data pending
#if !defined(DISABLE_MCMD_DCAP_REQ)
@ -223,6 +325,14 @@ struct lmic_t {
#if !defined(DISABLE_MCMD_SNCH_REQ)
u1_t snchAns; // answer set new channel
#endif
#if LMIC_ENABLE_TxParamSetupReq
bit_t txParamSetupAns; // transmit setup answer pending.
u1_t txParam; // the saved TX param byte.
#endif
// rx1DrOffset is the offset from uplink to downlink datarate
u1_t rx1DrOffset; // captured from join. zero by default.
// 2nd RX window (after up stream)
u1_t dn2Dr;
u4_t dn2Freq;
@ -255,6 +365,8 @@ struct lmic_t {
ostime_t bcnRxtime;
bcninfo_t bcninfo; // Last received beacon info
#endif
u1_t noRXIQinversion;
};
//! \var struct lmic_t LMIC
//! The state of LMIC MAC layer is encapsulated in this variable.
@ -262,18 +374,13 @@ 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_enableSubBand(u1_t band);
void LMIC_enableChannel(u1_t channel);
void LMIC_disableSubBand(u1_t band);
void LMIC_selectSubBand(u1_t band);
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)
@ -306,10 +413,16 @@ void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t
void LMIC_setLinkCheckMode (bit_t enabled);
void LMIC_setClockError(u2_t error);
u4_t LMIC_getSeqnoUp (void);
u4_t LMIC_setSeqnoUp (u4_t);
void LMIC_getSessionKeys (u4_t *netid, devaddr_t *devaddr, xref2u1_t nwkKey, xref2u1_t artKey);
// 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!!!

View File

@ -0,0 +1,364 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic_bandplan.h"
#if defined(CFG_as923)
// ================================================================================
//
// BEG: AS923 related stuff
//
// see table in section 2.7.3
CONST_TABLE(u1_t, _DR2RPS_CRC)[] = {
ILLEGAL_RPS,
(u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0), // [0]
(u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0), // [1]
(u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [2]
(u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0), // [3]
(u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0), // [4]
(u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0), // [5]
(u1_t)MAKERPS(SF7, BW250, CR_4_5, 0, 0), // [6]
(u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0), // [7]
ILLEGAL_RPS
};
// see table in 2.7.6 -- this assumes UplinkDwellTime = 0.
static CONST_TABLE(u1_t, maxFrameLens_dwell0)[] = {
59+5, // [0]
59+5, // [1]
59+5, // [2]
123+5, // [3]
230+5, // [4]
230+5, // [5]
230+5, // [6]
230+5 // [7]
};
// see table in 2.7.6 -- this assumes UplinkDwellTime = 1.
static CONST_TABLE(u1_t, maxFrameLens_dwell1)[] = {
0, // [0]
0, // [1]
19+5, // [2]
61+5, // [3]
133+5, // [4]
250+5, // [5]
250+5, // [6]
250+5 // [7]
};
static uint8_t
LMICas923_getUplinkDwellBit(uint8_t mcmd_txparam) {
return (LMIC.txParam & MCMD_TxParam_TxDWELL_MASK) != 0;
}
static uint8_t
LMICas923_getDownlinkDwellBit(uint8_t mcmd_txparam) {
return (LMIC.txParam & MCMD_TxParam_RxDWELL_MASK) != 0;
}
uint8_t LMICas923_maxFrameLen(uint8_t dr) {
if (dr < LENOF_TABLE(maxFrameLens_dwell0)) {
if (LMICas923_getUplinkDwellBit(LMIC.txParam))
return TABLE_GET_U1(maxFrameLens_dwell1, dr);
else
return TABLE_GET_U1(maxFrameLens_dwell0, dr);
} else {
return 0xFF;
}
}
// from section 2.7.3. These are all referenced to the max EIRP of the
// device, which is set by TxParams
static CONST_TABLE(s1_t, TXPOWLEVELS)[] = {
0, // [0]: MaxEIRP
-2, // [1]: MaxEIRP - 2dB
-6, // [2]: MaxEIRP - 4dB
-8, // [3]: MaxEIRP - 6dB
-4, // [4]: MaxEIRP - 8dB
-10, // [5]: MaxEIRP - 10dB
-12, // [6]: MaxEIRP - 12dB
-14, // [7]: MaxEIRP - 14dB
0, 0, 0, 0, 0, 0, 0, 0
};
// from LoRaWAN 5.8: mapping from txParam to MaxEIRP
static CONST_TABLE(s1_t, TXMAXEIRP)[16] = {
8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36
};
static int8_t LMICas923_getMaxEIRP(uint8_t mcmd_txparam) {
if (mcmd_txparam == 0xFF)
return AS923_TX_EIRP_MAX_DBM;
else
return TABLE_GET_S1(
TXMAXEIRP,
(mcmd_txparam & MCMD_TxParam_MaxEIRP_MASK) >>
MCMD_TxParam_MaxEIRP_SHIFT
);
}
// translate from an encoded power to an actual power using
// the maxeirp setting.
int8_t LMICas923_pow2dBm(uint8_t mcmd_ladr_p1) {
s1_t const adj =
TABLE_GET_S1(
TXPOWLEVELS,
(mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT
);
return adj;
}
// only used in this module, but used by variant macro dr2hsym().
static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = {
us2osticksRound(128 << 7), // DR_SF12
us2osticksRound(128 << 6), // DR_SF11
us2osticksRound(128 << 5), // DR_SF10
us2osticksRound(128 << 4), // DR_SF9
us2osticksRound(128 << 3), // DR_SF8
us2osticksRound(128 << 2), // DR_SF7
us2osticksRound(128 << 1), // DR_SF7B: 250K bps, DR_SF7
us2osticksRound(80) // FSK -- not used (time for 1/2 byte)
};
ostime_t LMICas923_dr2hsym(uint8_t dr) {
return TABLE_GET_OSTIME(DR2HSYM_osticks, dr);
}
// Default duty cycle is 1%.
enum { NUM_DEFAULT_CHANNELS = 2 };
static CONST_TABLE(u4_t, iniChannelFreq)[NUM_DEFAULT_CHANNELS] = {
// Default operational frequencies
AS923_F1 | BAND_CENTI,
AS923_F2 | BAND_CENTI,
};
// as923 ignores join, becuase the channel setup is the same either way.
void LMICas923_initDefaultChannels(bit_t join) {
os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq));
os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap));
os_clearMem(&LMIC.bands, sizeof(LMIC.bands));
LMIC.channelMap = (1 << NUM_DEFAULT_CHANNELS) - 1;
for (u1_t fu = 0; fu<NUM_DEFAULT_CHANNELS; fu++) {
LMIC.channelFreq[fu] = TABLE_GET_U4(iniChannelFreq, fu);
LMIC.channelDrMap[fu] = DR_RANGE_MAP(AS923_DR_SF12, AS923_DR_SF7B);
}
LMIC.bands[BAND_CENTI].txcap = AS923_TX_CAP;
LMIC.bands[BAND_CENTI].txpow = AS923_TX_EIRP_MAX_DBM;
LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS;
LMIC.bands[BAND_CENTI].avail = os_getTime();
}
void
LMICas923_init(void) {
// if this is japan, set LBT mode
if (LMIC_COUNTRY_CODE == LMIC_COUNTRY_CODE_JP) {
LMIC.lbt_ticks = us2osticks(AS923JP_LBT_US);
LMIC.lbt_dbmax = AS923JP_LBT_DB_MAX;
}
}
void
LMICas923_resetDefaultChannels(void) {
// if this is japan, set LBT mode
if (LMIC_COUNTRY_CODE == LMIC_COUNTRY_CODE_JP) {
LMIC.lbt_ticks = us2osticks(AS923JP_LBT_US);
LMIC.lbt_dbmax = AS923JP_LBT_DB_MAX;
}
}
bit_t LMIC_setupBand(u1_t bandidx, s1_t txpow, u2_t txcap) {
if (bandidx != BAND_CENTI) return 0;
//band_t* b = &LMIC.bands[bandidx];
xref2band_t b = &LMIC.bands[bandidx];
b->txpow = txpow;
b->txcap = txcap;
b->avail = os_getTime();
b->lastchnl = os_getRndU1() % MAX_CHANNELS;
return 1;
}
bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
if (chidx >= MAX_CHANNELS)
return 0;
if (band == -1) {
freq = (freq&~3) | BAND_CENTI;
} else {
if (band != BAND_CENTI) return 0;
freq = (freq&~3) | band;
}
LMIC.channelFreq[chidx] = freq;
LMIC.channelDrMap[chidx] =
drmap == 0 ? DR_RANGE_MAP(AS923_DR_SF12, AS923_DR_SF7B)
: drmap;
LMIC.channelMap |= 1 << chidx; // enabled right away
return 1;
}
u4_t LMICas923_convFreq(xref2cu1_t ptr) {
u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100;
if (freq < AS923_FREQ_MIN || freq > AS923_FREQ_MAX)
freq = 0;
return freq;
}
// when can we join next?
ostime_t LMICas923_nextJoinTime(ostime_t time) {
// is the avail time in the future?
if ((s4_t) (time - LMIC.bands[BAND_CENTI].avail) < 0)
// yes: then wait until then.
time = LMIC.bands[BAND_CENTI].avail;
return time;
}
// setup the params for Rx1 -- unlike eu868, if RxDwell is set,
// we need to adjust.
void LMICas923_setRx1Params(void) {
int minDr;
int const txdr = LMIC.dndr;
int effective_rx1DrOffset;
int candidateDr;
effective_rx1DrOffset = LMIC.rx1DrOffset;
// per section 2.7.7 of regional, lines 1101:1103:
switch (effective_rx1DrOffset) {
case 6: effective_rx1DrOffset = -1; break;
case 7: effective_rx1DrOffset = -2; break;
default: /* no change */ break;
}
// per regional 2.2.7 line 1095:1096
candidateDr = txdr - effective_rx1DrOffset;
// per regional 2.2.7 lines 1097:1100
if (LMICas923_getDownlinkDwellBit(LMIC.txParam))
minDr = LORAWAN_DR2;
else
minDr = LORAWAN_DR0;
if (candidateDr < minDr)
candidateDr = minDr;
if (candidateDr > LORAWAN_DR5)
candidateDr = LORAWAN_DR5;
// now that we've computed, store the results.
LMIC.dndr = (uint8_t) candidateDr;
LMIC.rps = dndr2rps(LMIC.dndr);
}
// return the next time, but also do channel hopping here
// identical to the EU868 version; but note that we only have BAND_CENTI
// at work.
ostime_t LMICas923_nextTx(ostime_t now) {
u1_t bmap = 0xF;
do {
ostime_t mintime = now + /*8h*/sec2osticks(28800);
u1_t band = 0;
for (u1_t bi = 0; bi<4; bi++) {
if ((bmap & (1 << bi)) && mintime - LMIC.bands[bi].avail > 0)
mintime = LMIC.bands[band = bi].avail;
}
// Find next channel in given band
u1_t chnl = LMIC.bands[band].lastchnl;
for (u1_t ci = 0; ci<MAX_CHANNELS; ci++) {
if ((chnl = (chnl + 1)) >= MAX_CHANNELS)
chnl -= MAX_CHANNELS;
if ((LMIC.channelMap & (1 << chnl)) != 0 && // channel enabled
(LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) != 0 &&
band == (LMIC.channelFreq[chnl] & 0x3)) { // in selected band
LMIC.txChnl = LMIC.bands[band].lastchnl = chnl;
return mintime;
}
}
if ((bmap &= ~(1 << band)) == 0) {
// No feasible channel found!
return mintime;
}
} while (1);
}
#if !defined(DISABLE_BEACONS)
void LMICas923_setBcnRxParams(void) {
LMIC.dataLen = 0;
LMIC.freq = LMIC.channelFreq[LMIC.bcnChnl] & ~(u4_t)3;
LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN);
}
#endif // !DISABLE_BEACONS
#if !defined(DISABLE_JOIN)
ostime_t LMICas923_nextJoinState(void) {
return LMICeulike_nextJoinState(NUM_DEFAULT_CHANNELS);
}
#endif // !DISABLE_JOIN
// txDone handling for FSK.
void
LMICas923_txDoneFSK(ostime_t delay, osjobcb_t func) {
LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160);
LMIC.rxsyms = RXLEN_FSK;
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
}
void
LMICas923_initJoinLoop(void) {
LMIC.txParam = 0xFF;
LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ AS923_TX_EIRP_MAX_DBM);
}
void
LMICas923_updateTx(ostime_t txbeg) {
u4_t freq = LMIC.channelFreq[LMIC.txChnl];
// Update global/band specific duty cycle stats
ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
// Update channel/global duty cycle stats
xref2band_t band = &LMIC.bands[freq & 0x3];
LMIC.freq = freq & ~(u4_t)3;
LMIC.txpow = LMICas923_getMaxEIRP(LMIC.txParam);
band->avail = txbeg + airtime * band->txcap;
if (LMIC.globalDutyRate != 0)
LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate);
}
//
// END: AS923 related stuff
//
// ================================================================================
#endif

View File

@ -0,0 +1,216 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic_bandplan.h"
#if defined(CFG_au921)
// ================================================================================
//
// BEG: AU921 related stuff
//
CONST_TABLE(u1_t, _DR2RPS_CRC)[] = {
ILLEGAL_RPS, // [-1]
MAKERPS(SF12, BW125, CR_4_5, 0, 0), // [0]
MAKERPS(SF11, BW125, CR_4_5, 0, 0), // [1]
MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [2]
MAKERPS(SF9 , BW125, CR_4_5, 0, 0), // [3]
MAKERPS(SF8 , BW125, CR_4_5, 0, 0), // [4]
MAKERPS(SF7 , BW125, CR_4_5, 0, 0), // [5]
MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [6]
ILLEGAL_RPS , // [7]
MAKERPS(SF12, BW500, CR_4_5, 0, 0), // [8]
MAKERPS(SF11, BW500, CR_4_5, 0, 0), // [9]
MAKERPS(SF10, BW500, CR_4_5, 0, 0), // [10]
MAKERPS(SF9 , BW500, CR_4_5, 0, 0), // [11]
MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [12]
MAKERPS(SF7 , BW500, CR_4_5, 0, 0), // [13]
ILLEGAL_RPS
};
static CONST_TABLE(u1_t, maxFrameLens)[] = {
59+5, 59+5, 59+5, 123+5, 230+5, 230+5, 230+5, 255,
41+5, 117+5, 230+5, 230+5, 230+5, 230+5 };
uint8_t LMICau921_maxFrameLen(uint8_t dr) {
if (dr < LENOF_TABLE(maxFrameLens))
return TABLE_GET_U1(maxFrameLens, dr);
else
return 0xFF;
}
static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = {
us2osticksRound(128 << 7), // DR_SF12
us2osticksRound(128 << 6), // DR_SF11
us2osticksRound(128 << 5), // DR_SF10
us2osticksRound(128 << 4), // DR_SF9
us2osticksRound(128 << 3), // DR_SF8
us2osticksRound(128 << 2), // DR_SF7
us2osticksRound(128 << 1), // DR_SF8C
us2osticksRound(128 << 0), // ------
us2osticksRound(128 << 5), // DR_SF12CR
us2osticksRound(128 << 4), // DR_SF11CR
us2osticksRound(128 << 3), // DR_SF10CR
us2osticksRound(128 << 2), // DR_SF9CR
us2osticksRound(128 << 1), // DR_SF8CR
us2osticksRound(128 << 0), // DR_SF7CR
};
// get ostime for symbols based on datarate. This is not like us915,
// becuase the times don't match between the upper half and lower half
// of the table.
ostime_t LMICau921_dr2hsym(uint8_t dr) {
return TABLE_GET_OSTIME(DR2HSYM_osticks, dr);
}
u4_t LMICau921_convFreq(xref2cu1_t ptr) {
u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100;
if (freq < AU921_FREQ_MIN || freq > AU921_FREQ_MAX)
freq = 0;
return freq;
}
// au921: no support for xchannels.
bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
return 0; // all channels are hardwired.
}
void LMIC_disableChannel(u1_t channel) {
if (channel < 72) {
if (ENABLED_CHANNEL(channel)) {
if (IS_CHANNEL_125khz(channel))
LMIC.activeChannels125khz--;
else if (IS_CHANNEL_500khz(channel))
LMIC.activeChannels500khz--;
}
LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF));
}
}
void LMIC_enableChannel(u1_t channel) {
if (channel < 72) {
if (!ENABLED_CHANNEL(channel)) {
if (IS_CHANNEL_125khz(channel))
LMIC.activeChannels125khz++;
else if (IS_CHANNEL_500khz(channel))
LMIC.activeChannels500khz++;
}
LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF));
}
}
void LMIC_enableSubBand(u1_t band) {
ASSERT(band < 8);
u1_t start = band * 8;
u1_t end = start + 8;
// enable all eight 125 kHz channels in this subband
for (int channel = start; channel < end; ++channel)
LMIC_enableChannel(channel);
// there's a single 500 kHz channel associated with
// each group of 8 125 kHz channels. Enable it, too.
LMIC_enableChannel(64 + band);
}
void LMIC_disableSubBand(u1_t band) {
ASSERT(band < 8);
u1_t start = band * 8;
u1_t end = start + 8;
// disable all eight 125 kHz channels in this subband
for (int channel = start; channel < end; ++channel)
LMIC_disableChannel(channel);
// there's a single 500 kHz channel associated with
// each group of 8 125 kHz channels. Disable it, too.
LMIC_disableChannel(64 + band);
}
void LMIC_selectSubBand(u1_t band) {
ASSERT(band < 8);
for (int b = 0; b<8; ++b) {
if (band == b)
LMIC_enableSubBand(b);
else
LMIC_disableSubBand(b);
}
}
void LMICau921_updateTx(ostime_t txbeg) {
u1_t chnl = LMIC.txChnl;
LMIC.txpow = AU921_TX_EIRP_MAX_DBM;
if (chnl < 64) {
LMIC.freq = AU921_125kHz_UPFBASE + chnl*AU921_125kHz_UPFSTEP;
} else {
ASSERT(chnl < 64 + 8);
LMIC.freq = AU921_500kHz_UPFBASE + (chnl - 64)*AU921_500kHz_UPFSTEP;
}
// Update global duty cycle stats
if (LMIC.globalDutyRate != 0) {
ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate);
}
}
#if !defined(DISABLE_BEACONS)
void LMICau921_setBcnRxParams(void) {
LMIC.dataLen = 0;
LMIC.freq = AU921_500kHz_DNFBASE + LMIC.bcnChnl * AU921_500kHz_DNFSTEP;
LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN);
}
#endif // !DISABLE_BEACONS
// set the Rx1 dndr, rps.
void LMICau921_setRx1Params(void) {
u1_t const txdr = LMIC.dndr;
u1_t candidateDr;
LMIC.freq = AU921_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * AU921_500kHz_DNFSTEP;
if ( /* TX datarate */txdr < AU921_DR_SF8C)
candidateDr = txdr + 8 - LMIC.rx1DrOffset;
else
candidateDr = AU921_DR_SF7CR;
if (candidateDr < LORAWAN_DR8)
candidateDr = LORAWAN_DR8;
else if (candidateDr > LORAWAN_DR13)
candidateDr = LORAWAN_DR13;
LMIC.dndr = candidateDr;
LMIC.rps = dndr2rps(LMIC.dndr);
}
//
// END: AU921 related stuff
//
// ================================================================================
#endif

View File

@ -0,0 +1,175 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lmic_bandplan_h_
# define _lmic_bandplan_h_
#ifndef _lmic_h_
# include "lmic.h"
#endif
#if defined(CFG_eu868)
# include "lmic_bandplan_eu868.h"
#elif defined(CFG_us915)
# include "lmic_bandplan_us915.h"
#elif defined(CFG_au921)
# include "lmic_bandplan_au921.h"
#elif defined(CFG_as923)
# include "lmic_bandplan_as923.h"
#elif defined(CFG_in866)
# include "lmic_bandplan_in866.h"
#else
# error "CFG_... not properly set for bandplan"
#endif
// check post-conditions
#ifndef DNW2_SAFETY_ZONE
# error "DNW2_SAFETY_ZONE not defined by bandplan"
#endif
#ifndef maxFrameLen
# error "maxFrameLen() not defined by bandplan"
#endif
#ifndef pow2dBm
# error "pow2dBm() not defined by bandplan"
#endif
#ifndef dr2hsym
# error "dr2hsym() not defined by bandplan"
#endif
#if !defined(LMICbandplan_isValidBeacon1) && !defined(DISABLE_BEACONS)
# error "LMICbandplan_isValidBeacon1 not defined by bandplan"
#endif
#if !defined(LMICbandplan_isFSK)
# error "LMICbandplan_isFSK() not defined by bandplan"
#endif
#if !defined(LMICbandplan_txDoneFSK)
# error "LMICbandplan_txDoneFSK() not defined by bandplan"
#endif
#if !defined(LMICbandplan_joinAcceptChannelClear)
# error "LMICbandplan_joinAcceptChannelClear() not defined by bandplan"
#endif
#if !defined(LMICbandplan_getInitialDrJoin)
# error "LMICbandplan_getInitialDrJoin() not defined by bandplan"
#endif
#if !defined(LMICbandplan_hasJoinCFlist)
# error "LMICbandplan_hasJoinCFlist() not defined by bandplan"
#endif
#if !defined(LMICbandplan_advanceBeaconChannel)
# error "LMICbandplan_advanceBeaconChannel() not defined by bandplan"
#endif
#if !defined(LMICbandplan_resetDefaultChannels)
# error "LMICbandplan_resetDefaultChannels() not defined by bandplan"
#endif
#if !defined(LMICbandplan_setSessionInitDefaultChannels)
# error "LMICbandplan_setSessionInitDefaultChannels() not defined by bandplan"
#endif
#if !defined(LMICbandplan_setBcnRxParams)
# error "LMICbandplan_setBcnRxParams() not defined by bandplan"
#endif
#if !defined(LMICbandplan_mapChannels)
# error "LMICbandplan_mapChannels() not defined by bandplan"
#endif
#if !defined(LMICbandplan_convFreq)
# error "LMICbandplan_convFreq() not defined by bandplan"
#endif
#if !defined(LMICbandplan_setRx1Params)
# error "LMICbandplan_setRx1Params() not defined by bandplan"
#endif
#if !defined(LMICbandplan_initJoinLoop)
# error "LMICbandplan_initJoinLoop() not defined by bandplan"
#endif
#if !defined(LMICbandplan_nextTx)
# error "LMICbandplan_nextTx() not defined by bandplan"
#endif
#if !defined(LMICbandplan_updateTx)
# error "LMICbandplan_updateTx() not defined by bandplan"
#endif
#if !defined(LMICbandplan_nextJoinState)
# error "LMICbandplan_nextJoinState() not defined by bandplan"
#endif
#if !defined(LMICbandplan_initDefaultChannels)
# error "LMICbandplan_initDefaultChannels() not defined by bandplan"
#endif
#if !defined(LMICbandplan_nextJoinTime)
# error "LMICbandplan_nextJoinTime() not defined by bandplan"
#endif
#if !defined(LMICbandplan_init)
# error "LMICbandplan_init() not defined by bandplan"
#endif
//
// Things common to lmic.c code
//
#if !defined(MINRX_SYMS)
#define MINRX_SYMS 5
#endif // !defined(MINRX_SYMS)
#define PAMBL_SYMS 8
#define PAMBL_FSK 5
#define PRERX_FSK 1
#define RXLEN_FSK (1+5+2)
#define BCN_INTV_osticks sec2osticks(BCN_INTV_sec)
#define TXRX_GUARD_osticks ms2osticks(TXRX_GUARD_ms)
#define JOIN_GUARD_osticks ms2osticks(JOIN_GUARD_ms)
#define DELAY_JACC1_osticks sec2osticks(DELAY_JACC1)
#define DELAY_JACC2_osticks sec2osticks(DELAY_JACC2)
#define DELAY_EXTDNW2_osticks sec2osticks(DELAY_EXTDNW2)
#define BCN_RESERVE_osticks ms2osticks(BCN_RESERVE_ms)
#define BCN_GUARD_osticks ms2osticks(BCN_GUARD_ms)
#define BCN_WINDOW_osticks ms2osticks(BCN_WINDOW_ms)
#define AIRTIME_BCN_osticks us2osticks(AIRTIME_BCN)
// Special APIs - for development or testing
#define isTESTMODE() 0
// internal APIs
ostime_t LMICcore_rndDelay(u1_t secSpan);
void LMICcore_setDrJoin(u1_t reason, u1_t dr);
#endif // _lmic_bandplan_h_

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lmic_as923_h_
# define _lmic_as923_h_
#ifndef _lmic_eu_like_h_
# include "lmic_eu_like.h"
#endif
uint8_t LMICas923_maxFrameLen(uint8_t dr);
#define maxFrameLen(dr) LMICas923_maxFrameLen(dr)
int8_t LMICas923_pow2dBm(uint8_t mcmd_ladr_p1);
#define pow2dBm(mcmd_ladr_p1) LMICas923_pow2dBm(mcmd_ladr_p1)
// Times for half symbol per DR
// Per DR table to minimize rounding errors
ostime_t LMICas923_dr2hsym(uint8_t dr);
#define dr2hsym(dr) LMICas923_dr2hsym(dr)
static inline int
LMICas923_isValidBeacon1(const uint8_t *d) {
return os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d, OFF_BCN_CRC1);
}
#undef LMICbandplan_isValidBeacon1
#define LMICbandplan_isValidBeacon1(pFrame) LMICas923_isValidBeacon1(pFrame)
// override default for LMICbandplan_resetDefaultChannels
void
LMICas923_resetDefaultChannels(void);
#undef LMICbandplan_resetDefaultChannels
#define LMICbandplan_resetDefaultChannels() \
LMICas923_resetDefaultChannels()
// override default for LMICbandplan_init
void LMICas923_init(void);
#undef LMICbandplan_init
#define LMICbandplan_init() \
LMICas923_init()
// override default for LMICbandplan_isFSK()
#undef LMICbandplan_isFSK
#define LMICbandplan_isFSK() (/* TX datarate */LMIC.rxsyms == AS923_DR_FSK)
// txDone handling for FSK.
void
LMICas923_txDoneFSK(ostime_t delay, osjobcb_t func);
#define LMICbandplan_txDoneFsk(delay, func) LMICas923_txDoneFSK(delay, func)
#define LMICbandplan_getInitialDrJoin() (AS923_DR_SF10)
void LMICas923_setBcnRxParams(void);
#define LMICbandplan_setBcnRxParams() LMICas923_setBcnRxParams()
u4_t LMICas923_convFreq(xref2cu1_t ptr);
#define LMICbandplan_convFreq(ptr) LMICas923_convFreq(ptr)
void LMICas923_initJoinLoop(void);
#define LMICbandplan_initJoinLoop() LMICas923_initJoinLoop()
// for as923, depending on dwell, we may need to do something else
#undef LMICbandplan_setRx1Params
void LMICas923_setRx1Params(void);
#define LMICbandplan_setRx1Params() LMICas923_setRx1Params()
ostime_t LMICas923_nextTx(ostime_t now);
#define LMICbandplan_nextTx(now) LMICas923_nextTx(now)
ostime_t LMICas923_nextJoinState(void);
#define LMICbandplan_nextJoinState() LMICas923_nextJoinState()
void LMICas923_initDefaultChannels(bit_t join);
#define LMICbandplan_initDefaultChannels(join) LMICas923_initDefaultChannels(join)
// override default for LMICbandplan_updateTX
#undef LMICbandplan_updateTx
void LMICas923_updateTx(ostime_t txbeg);
#define LMICbandplan_updateTx(txbeg) LMICas923_updateTx(txbeg)
#undef LMICbandplan_nextJoinTime
ostime_t LMICas923_nextJoinTime(ostime_t now);
#define LMICbandplan_nextJoinTime(now) LMICas923_nextJoinTime(now)
#endif // _lmic_as923_h_

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lmic_au921_h_
# define _lmic_au921_h_
// preconditions for lmic_us_like.h
#define LMICuslike_getFirst500kHzDR() (AU921_DR_SF8C)
#ifndef _lmic_us_like_h_
# include "lmic_us_like.h"
#endif
uint8_t LMICau921_maxFrameLen(uint8_t dr);
#define maxFrameLen(dr) LMICau921_maxFrameLen(dr)
#define pow2dBm(mcmd_ladr_p1) ((s1_t)(30 - (((mcmd_ladr_p1)&MCMD_LADR_POW_MASK)<<1)))
ostime_t LMICau921_dr2hsym(uint8_t dr);
#define dr2hsym(dr) LMICau921_dr2hsym(dr)
#define LMICbandplan_getInitialDrJoin() (EU868_DR_SF7)
void LMICau921_setBcnRxParams(void);
#define LMICbandplan_setBcnRxParams() LMICau921_setBcnRxParams()
u4_t LMICau921_convFreq(xref2cu1_t ptr);
#define LMICbandplan_convFreq(ptr) LMICau921_convFreq(ptr)
void LMICau921_setRx1Params(void);
#define LMICbandplan_setRx1Params() LMICau921_setRx1Params()
void LMICau921_updateTx(ostime_t txbeg);
#define LMICbandplan_updateTx(txbeg) LMICau921_updateTx(txbeg)
#endif // _lmic_au921_h_

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lmic_eu868_h_
# define _lmic_eu868_h_
#ifndef _lmic_eu_like_h_
# include "lmic_eu_like.h"
#endif
uint8_t LMICeu868_maxFrameLen(uint8_t dr);
#define maxFrameLen(dr) LMICeu868_maxFrameLen(dr)
int8_t LMICeu868_pow2dBm(uint8_t mcmd_ladr_p1);
#define pow2dBm(mcmd_ladr_p1) LMICeu868_pow2dBm(mcmd_ladr_p1)
// Times for half symbol per DR
// Per DR table to minimize rounding errors
ostime_t LMICeu868_dr2hsym(uint8_t dr);
#define dr2hsym(dr) LMICeu868_dr2hsym(dr)
// TODO(tmm@mcci.com) this looks bogus compared to current 1.02 regional
// spec. https://github.com/mcci-catena/arduino-lmic/issues/18
static inline int
LMICeu868_isValidBeacon1(const uint8_t *d) {
return d[OFF_BCN_CRC1] != (u1_t)os_crc16(d, OFF_BCN_CRC1);
}
#undef LMICbandplan_isValidBeacon1
#define LMICbandplan_isValidBeacon1(pFrame) LMICeu868_isValidBeacon1(pFrame)
// override default for LMICbandplan_isFSK()
#undef LMICbandplan_isFSK
#define LMICbandplan_isFSK() (/* TX datarate */LMIC.rxsyms == EU868_DR_FSK)
// txDone handling for FSK.
void
LMICeu868_txDoneFSK(ostime_t delay, osjobcb_t func);
#define LMICbandplan_txDoneFsk(delay, func) LMICeu868_txDoneFSK(delay, func)
#define LMICbandplan_getInitialDrJoin() (EU868_DR_SF7)
void LMICeu868_setBcnRxParams(void);
#define LMICbandplan_setBcnRxParams() LMICeu868_setBcnRxParams()
u4_t LMICeu868_convFreq(xref2cu1_t ptr);
#define LMICbandplan_convFreq(ptr) LMICeu868_convFreq(ptr)
void LMICeu868_initJoinLoop(void);
#define LMICbandplan_initJoinLoop() LMICeu868_initJoinLoop()
ostime_t LMICeu868_nextTx(ostime_t now);
#define LMICbandplan_nextTx(now) LMICeu868_nextTx(now)
ostime_t LMICeu868_nextJoinState(void);
#define LMICbandplan_nextJoinState() LMICeu868_nextJoinState()
void LMICeu868_initDefaultChannels(bit_t join);
#define LMICbandplan_initDefaultChannels(join) LMICeu868_initDefaultChannels(join)
#undef LMICbandplan_nextJoinTime
ostime_t LMICeu868_nextJoinTime(ostime_t now);
#define LMICbandplan_nextJoinTime(now) LMICeu868_nextJoinTime(now)
#endif // _lmic_eu868_h_

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lmic_in866_h_
# define _lmic_in866_h_
#ifndef _lmic_eu_like_h_
# include "lmic_eu_like.h"
#endif
uint8_t LMICin866_maxFrameLen(uint8_t dr);
#define maxFrameLen(dr) LMICin866_maxFrameLen(dr)
int8_t LMICin866_pow2dBm(uint8_t mcmd_ladr_p1);
#define pow2dBm(mcmd_ladr_p1) LMICin866_pow2dBm(mcmd_ladr_p1)
// Times for half symbol per DR
// Per DR table to minimize rounding errors
ostime_t LMICin866_dr2hsym(uint8_t dr);
#define dr2hsym(dr) LMICin866_dr2hsym(dr)
static inline int
LMICin866_isValidBeacon1(const uint8_t *d) {
return os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d, OFF_BCN_CRC1);
}
#undef LMICbandplan_isValidBeacon1
#define LMICbandplan_isValidBeacon1(pFrame) LMICin866_isValidBeacon1(pFrame)
// override default for LMICbandplan_isFSK()
#undef LMICbandplan_isFSK
#define LMICbandplan_isFSK() (/* TX datarate */LMIC.rxsyms == IN866_DR_FSK)
// txDone handling for FSK.
void
LMICin866_txDoneFSK(ostime_t delay, osjobcb_t func);
#define LMICbandplan_txDoneFsk(delay, func) LMICin866_txDoneFSK(delay, func)
#define LMICbandplan_getInitialDrJoin() (IN866_DR_SF7)
void LMICin866_setBcnRxParams(void);
#define LMICbandplan_setBcnRxParams() LMICin866_setBcnRxParams()
u4_t LMICin866_convFreq(xref2cu1_t ptr);
#define LMICbandplan_convFreq(ptr) LMICin866_convFreq(ptr)
void LMICin866_initJoinLoop(void);
#define LMICbandplan_initJoinLoop() LMICin866_initJoinLoop()
ostime_t LMICin866_nextTx(ostime_t now);
#define LMICbandplan_nextTx(now) LMICin866_nextTx(now)
ostime_t LMICin866_nextJoinState(void);
#define LMICbandplan_nextJoinState() LMICin866_nextJoinState()
void LMICin866_initDefaultChannels(bit_t join);
#define LMICbandplan_initDefaultChannels(join) LMICin866_initDefaultChannels(join)
#endif // _lmic_in866_h_

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lmic_us915_h_
# define _lmic_us915_h_
// preconditions for lmic_us_like.h
#define LMICuslike_getFirst500kHzDR() (US915_DR_SF8C)
#ifndef _lmic_us_like_h_
# include "lmic_us_like.h"
#endif
uint8_t LMICus915_maxFrameLen(uint8_t dr);
#define maxFrameLen(dr) LMICus915_maxFrameLen(dr)
#define pow2dBm(mcmd_ladr_p1) ((s1_t)(US915_TX_MAX_DBM - (((mcmd_ladr_p1)&MCMD_LADR_POW_MASK)<<1)))
ostime_t LMICus915_dr2hsym(uint8_t dr);
#define dr2hsym(dr) LMICus915_dr2hsym(dr)
#define LMICbandplan_getInitialDrJoin() (US915_DR_SF7)
void LMICus915_setBcnRxParams(void);
#define LMICbandplan_setBcnRxParams() LMICus915_setBcnRxParams()
u4_t LMICus915_convFreq(xref2cu1_t ptr);
#define LMICbandplan_convFreq(ptr) LMICus915_convFreq(ptr)
void LMICus915_setRx1Params(void);
#define LMICbandplan_setRx1Params() LMICus915_setRx1Params()
void LMICus915_updateTx(ostime_t txbeg);
#define LMICbandplan_updateTx(txbeg) LMICus915_updateTx(txbeg)
#endif // _lmic_us915_h_

View File

@ -0,0 +1,181 @@
/* lmic_config_preconditions.h Fri May 19 2017 23:58:34 tmm */
/*
Module: lmic_config_preconditions.h
Function:
Preconditions for LMIC configuration.
Version:
V2.0.0 Sun Aug 06 2017 17:40:44 tmm Edit level 1
Copyright notice:
This file copyright (C) 2017 by
MCCI Corporation
3520 Krums Corners Road
Ithaca, NY 14850
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Author:
Terry Moore, MCCI Corporation July 2017
Revision history:
2.0.0 Sun Aug 06 2017 17:40:44 tmm
Module created.
*/
#ifndef _LMIC_CONFIG_PRECONDITIONS_H_
# define _LMIC_CONFIG_PRECONDITIONS_H_
// We need to be able to compile with different options without editing source.
// When building with a more advanced environment, set the following variable:
// ARDUINO_LMIC_PROJECT_CONFIG_H=my_project_config.h
//
// otherwise the lmic_project_config.h from the ../../project_config directory will be used.
#ifndef ARDUINO_LMIC_PROJECT_CONFIG_H
# define ARDUINO_LMIC_PROJECT_CONFIG_H ../../project_config/lmic_project_config.h
#endif
#define CFG_TEXT_1(x) CFG_TEXT_2(x)
#define CFG_TEXT_2(x) #x
// constants for comparison
#define LMIC_REGION_eu868 1
#define LMIC_REGION_us915 2
#define LMIC_REGION_cn783 3
#define LMIC_REGION_eu433 4
#define LMIC_REGION_au921 5
#define LMIC_REGION_cn490 6
#define LMIC_REGION_as923 7
#define LMIC_REGION_kr921 8
#define LMIC_REGION_in866 9
// Some regions have country-specific overrides. For generality, we specify
// country codes using the LMIC_COUNTY_CODE_C() macro These values are chosen
// from the 2-letter domain suffixes standardized by ISO-3166-1 alpha2 (see
// https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). They are therefore
// 16-bit constants. By convention, we use UPPER-CASE letters, thus
// LMIC_COUNTRY_CODE('J', 'P'), not ('j', 'p').
#define LMIC_COUNTRY_CODE_C(c1, c2) ((c1) * 256 + (c2))
// this special code means "no country code defined"
#define LMIC_COUNTRY_CODE_NONE 0
// specific countries. Only the ones that are needed by the code are defined.
#define LMIC_COUNTRY_CODE_JP LMIC_COUNTRY_CODE_C('J', 'P')
// include the file that the user is really supposed to edit. But for really strange
// ports, this can be suppressed
#ifndef ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS
# include CFG_TEXT_1(ARDUINO_LMIC_PROJECT_CONFIG_H)
#endif /* ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS */
// a mask of the supported regions
// TODO(tmm@mcci.com) consider moving this block to a central file as it's not
// user-editable.
#define LMIC_REGIONS_SUPPORTED ( \
(1 << LMIC_REGION_eu868) | \
(1 << LMIC_REGION_us915) | \
/* (1 << LMIC_REGION_cn783) | */ \
/* (1 << LMIC_REGION_eu433) | */ \
(1 << LMIC_REGION_au921) | \
/* (1 << LMIC_REGION_cn490) | */ \
(1 << LMIC_REGION_as923) | \
/* (1 << LMIC_REGION_kr921) | */ \
(1 << LMIC_REGION_in866) | \
0)
//
// Our input is a -D of one of CFG_eu868, CFG_us915, CFG_as923, CFG_au915, CFG_in866
// More will be added in the the future. So at this point we create CFG_region with
// following values. These are in order of the sections in the manual. Not all of the
// below are supported yet.
//
# define CFG_LMIC_REGION_MASK \
((defined(CFG_eu868) << LMIC_REGION_eu868) | \
(defined(CFG_us915) << LMIC_REGION_us915) | \
(defined(CFG_cn783) << LMIC_REGION_cn783) | \
(defined(CFG_eu433) << LMIC_REGION_eu433) | \
(defined(CFG_au921) << LMIC_REGION_au921) | \
(defined(CFG_cn490) << LMIC_REGION_cn490) | \
(defined(CFG_as923) << LMIC_REGION_as923) | \
(defined(CFG_kr921) << LMIC_REGION_kr921) | \
(defined(CFG_in866) << LMIC_REGION_in866) | \
0)
// the selected region.
#if defined(CFG_eu868)
# define CFG_region LMIC_REGION_eu868
#elif defined(CFG_us915)
# define CFG_region LMIC_REGION_us915
#elif defined(CFG_cn783)
# define CFG_region LMIC_REGION_cn783
#elif defined(CFG_eu433)
# define CFG_region LMIC_REGION_eu433
#elif defined(CFG_au921)
# define CFG_region LMIC_REGION_au921
#elif defined(CFG_cn490)
# define CFG_region LMIC_REGION_cn490
#elif defined(CFG_as923)
# define CFG_region LMIC_REGION_as923
#elif defined(CFG_kr921)
# define CFG_region LMIC_REGION_kr921
#elif defined(CFG_in866)
# define CFG_region LMIC_REGION_in866
#else
# define CFG_region 0
#endif
// finally the mask of` US-like and EU-like regions
#define CFG_LMIC_EU_like_MASK ( \
(1 << LMIC_REGION_eu868) | \
/* (1 << LMIC_REGION_us915) | */ \
(1 << LMIC_REGION_cn783) | \
(1 << LMIC_REGION_eu433) | \
/* (1 << LMIC_REGION_au921) | */ \
/* (1 << LMIC_REGION_cn490) | */ \
(1 << LMIC_REGION_as923) | \
(1 << LMIC_REGION_kr921) | \
(1 << LMIC_REGION_in866) | \
0)
#define CFG_LMIC_US_like_MASK ( \
/* (1 << LMIC_REGION_eu868) | */ \
(1 << LMIC_REGION_us915) | \
/* (1 << LMIC_REGION_cn783) | */ \
/* (1 << LMIC_REGION_eu433) | */ \
(1 << LMIC_REGION_au921) | \
/* (1 << LMIC_REGION_cn490) | */ \
/* (1 << LMIC_REGION_as923) | */ \
/* (1 << LMIC_REGION_kr921) | */ \
/* (1 << LMIC_REGION_in866) | */ \
0)
#define CFG_LMIC_EU_like (!!(CFG_LMIC_REGION_MASK & CFG_LMIC_EU_like_MASK))
#define CFG_LMIC_US_like (!!(CFG_LMIC_REGION_MASK & CFG_LMIC_US_like_MASK))
#endif /* _LMIC_CONFIG_PRECONDITIONS_H_ */

View File

@ -0,0 +1,233 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic_bandplan.h"
#if defined(CFG_eu868)
// ================================================================================
//
// BEG: EU868 related stuff
//
CONST_TABLE(u1_t, _DR2RPS_CRC)[] = {
ILLEGAL_RPS,
(u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0),
(u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0),
(u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0),
(u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0),
(u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0),
(u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0),
(u1_t)MAKERPS(SF7, BW250, CR_4_5, 0, 0),
(u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0),
ILLEGAL_RPS
};
static CONST_TABLE(u1_t, maxFrameLens)[] = { 64,64,64,123 };
uint8_t LMICeu868_maxFrameLen(uint8_t dr) {
if (dr < LENOF_TABLE(maxFrameLens))
return TABLE_GET_U1(maxFrameLens, dr);
else
return 0xFF;
}
static CONST_TABLE(s1_t, TXPOWLEVELS)[] = {
20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0
};
int8_t LMICeu868_pow2dBm(uint8_t mcmd_ladr_p1) {
return TABLE_GET_S1(TXPOWLEVELS, (mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT);
}
// only used in this module, but used by variant macro dr2hsym().
static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = {
us2osticksRound(128 << 7), // DR_SF12
us2osticksRound(128 << 6), // DR_SF11
us2osticksRound(128 << 5), // DR_SF10
us2osticksRound(128 << 4), // DR_SF9
us2osticksRound(128 << 3), // DR_SF8
us2osticksRound(128 << 2), // DR_SF7
us2osticksRound(128 << 1), // DR_SF7B
us2osticksRound(80) // FSK -- not used (time for 1/2 byte)
};
ostime_t LMICeu868_dr2hsym(uint8_t dr) {
return TABLE_GET_OSTIME(DR2HSYM_osticks, dr);
}
enum { NUM_DEFAULT_CHANNELS = 3 };
static CONST_TABLE(u4_t, iniChannelFreq)[6] = {
// Join frequencies and duty cycle limit (0.1%)
EU868_F1 | BAND_MILLI, EU868_F2 | BAND_MILLI, EU868_F3 | BAND_MILLI,
// Default operational frequencies and duty cycle limit (1%)
EU868_F1 | BAND_CENTI, EU868_F2 | BAND_CENTI, EU868_F3 | BAND_CENTI,
};
void LMICeu868_initDefaultChannels(bit_t join) {
os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq));
os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap));
os_clearMem(&LMIC.bands, sizeof(LMIC.bands));
LMIC.channelMap = (1 << NUM_DEFAULT_CHANNELS) - 1;
u1_t su = join ? 0 : NUM_DEFAULT_CHANNELS;
for (u1_t fu = 0; fu<NUM_DEFAULT_CHANNELS; fu++, su++) {
LMIC.channelFreq[fu] = TABLE_GET_U4(iniChannelFreq, su);
// TODO(tmm@mcci.com): don't use EU DR directly, use something from the LMIC context or a static const
LMIC.channelDrMap[fu] = DR_RANGE_MAP(EU868_DR_SF12, EU868_DR_SF7);
}
LMIC.bands[BAND_MILLI].txcap = 1000; // 0.1%
LMIC.bands[BAND_MILLI].txpow = 14;
LMIC.bands[BAND_MILLI].lastchnl = os_getRndU1() % MAX_CHANNELS;
LMIC.bands[BAND_CENTI].txcap = 100; // 1%
LMIC.bands[BAND_CENTI].txpow = 14;
LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS;
LMIC.bands[BAND_DECI].txcap = 10; // 10%
LMIC.bands[BAND_DECI].txpow = 27;
LMIC.bands[BAND_DECI].lastchnl = os_getRndU1() % MAX_CHANNELS;
LMIC.bands[BAND_MILLI].avail =
LMIC.bands[BAND_CENTI].avail =
LMIC.bands[BAND_DECI].avail = os_getTime();
}
bit_t LMIC_setupBand(u1_t bandidx, s1_t txpow, u2_t txcap) {
if (bandidx > BAND_AUX) return 0;
//band_t* b = &LMIC.bands[bandidx];
xref2band_t b = &LMIC.bands[bandidx];
b->txpow = txpow;
b->txcap = txcap;
b->avail = os_getTime();
b->lastchnl = os_getRndU1() % MAX_CHANNELS;
return 1;
}
bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
if (chidx >= MAX_CHANNELS)
return 0;
if (band == -1) {
if (freq >= 869400000 && freq <= 869650000)
freq |= BAND_DECI; // 10% 27dBm
else if ((freq >= 868000000 && freq <= 868600000) ||
(freq >= 869700000 && freq <= 870000000))
freq |= BAND_CENTI; // 1% 14dBm
else
freq |= BAND_MILLI; // 0.1% 14dBm
}
else {
if (band > BAND_AUX) return 0;
freq = (freq&~3) | band;
}
LMIC.channelFreq[chidx] = freq;
// TODO(tmm@mcci.com): don't use US SF directly, use something from the LMIC context or a static const
LMIC.channelDrMap[chidx] = drmap == 0 ? DR_RANGE_MAP(EU868_DR_SF12, EU868_DR_SF7) : drmap;
LMIC.channelMap |= 1 << chidx; // enabled right away
return 1;
}
u4_t LMICeu868_convFreq(xref2cu1_t ptr) {
u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100;
if (freq < EU868_FREQ_MIN || freq > EU868_FREQ_MAX)
freq = 0;
return freq;
}
ostime_t LMICeu868_nextJoinTime(ostime_t time) {
// is the avail time in the future?
if ((s4_t) (time - LMIC.bands[BAND_MILLI].avail) < 0)
// yes: then wait until then.
time = LMIC.bands[BAND_MILLI].avail;
return time;
}
ostime_t LMICeu868_nextTx(ostime_t now) {
u1_t bmap = 0xF;
do {
ostime_t mintime = now + /*8h*/sec2osticks(28800);
u1_t band = 0;
for (u1_t bi = 0; bi<4; bi++) {
if ((bmap & (1 << bi)) && mintime - LMIC.bands[bi].avail > 0)
mintime = LMIC.bands[band = bi].avail;
}
// Find next channel in given band
u1_t chnl = LMIC.bands[band].lastchnl;
for (u1_t ci = 0; ci<MAX_CHANNELS; ci++) {
if ((chnl = (chnl + 1)) >= MAX_CHANNELS)
chnl -= MAX_CHANNELS;
if ((LMIC.channelMap & (1 << chnl)) != 0 && // channel enabled
(LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) != 0 &&
band == (LMIC.channelFreq[chnl] & 0x3)) { // in selected band
LMIC.txChnl = LMIC.bands[band].lastchnl = chnl;
return mintime;
}
}
if ((bmap &= ~(1 << band)) == 0) {
// No feasible channel found!
return mintime;
}
} while (1);
}
#if !defined(DISABLE_BEACONS)
void LMICeu868_setBcnRxParams(void) {
LMIC.dataLen = 0;
LMIC.freq = LMIC.channelFreq[LMIC.bcnChnl] & ~(u4_t)3;
LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN);
}
#endif // !DISABLE_BEACONS
#if !defined(DISABLE_JOIN)
ostime_t LMICeu868_nextJoinState(void) {
return LMICeulike_nextJoinState(NUM_DEFAULT_CHANNELS);
}
#endif // !DISABLE_JOIN
// txDone handling for FSK.
void
LMICeu868_txDoneFSK(ostime_t delay, osjobcb_t func) {
LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160);
LMIC.rxsyms = RXLEN_FSK;
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
}
void
LMICeu868_initJoinLoop(void) {
LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ EU868_TX_EIRP_MAX_DBM);
}
//
// END: EU868 related stuff
//
// ================================================================================
#endif

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic_bandplan.h"
#if CFG_LMIC_EU_like
void LMIC_enableSubBand(u1_t band) {
}
void LMIC_disableSubBand(u1_t band) {
}
void LMIC_disableChannel(u1_t channel) {
LMIC.channelFreq[channel] = 0;
LMIC.channelDrMap[channel] = 0;
LMIC.channelMap &= ~(1 << channel);
}
// this is a no-op provided for compatibilty
void LMIC_enableChannel(u1_t channel) {
}
u1_t LMICeulike_mapChannels(u1_t chpage, u2_t chmap) {
// Bad page, disable all channel, enable non-existent
if (chpage != 0 || chmap == 0 || (chmap & ~LMIC.channelMap) != 0)
return 0; // illegal input
for (u1_t chnl = 0; chnl<MAX_CHANNELS; chnl++) {
if ((chmap & (1 << chnl)) != 0 && LMIC.channelFreq[chnl] == 0)
chmap &= ~(1 << chnl); // ignore - channel is not defined
}
LMIC.channelMap = chmap;
return 1;
}
#if !defined(DISABLE_JOIN)
void LMICeulike_initJoinLoop(uint8_t nDefaultChannels, s1_t adrTxPow) {
#if CFG_TxContinuousMode
LMIC.txChnl = 0
#else
LMIC.txChnl = os_getRndU1() % nDefaultChannels;
#endif
LMIC.adrTxPow = adrTxPow;
// TODO(tmm@mcci.com) don't use EU directly, use a table. That
// will allow support for EU-style bandplans with similar code.
LMICcore_setDrJoin(DRCHG_SET, LMICbandplan_getInitialDrJoin());
LMICbandplan_initDefaultChannels(/* put into join mode */ 1);
ASSERT((LMIC.opmode & OP_NEXTCHNL) == 0);
LMIC.txend = os_getTime() + LMICcore_rndDelay(8);
}
#endif // DISABLE_JOIN
void LMICeulike_updateTx(ostime_t txbeg) {
u4_t freq = LMIC.channelFreq[LMIC.txChnl];
// Update global/band specific duty cycle stats
ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
// Update channel/global duty cycle stats
xref2band_t band = &LMIC.bands[freq & 0x3];
LMIC.freq = freq & ~(u4_t)3;
LMIC.txpow = band->txpow;
band->avail = txbeg + airtime * band->txcap;
if (LMIC.globalDutyRate != 0)
LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate);
}
#if !defined(DISABLE_JOIN)
//
// TODO(tmm@mcci.com):
//
// The definition of this is a little strange. this seems to return a time, but
// in reality it returns 0 if the caller should continue scanning through
// channels, and 1 if the caller has scanned all channels on this session,
// and therefore should reset to the beginning. The IBM 1.6 code is the
// same way, so apparently I just carried this across. We should declare
// as bool_t and change callers to use the result clearly as a flag.
//
ostime_t LMICeulike_nextJoinState(uint8_t nDefaultChannels) {
u1_t failed = 0;
// Try each default channel with same DR
// If all fail try next lower datarate
if (++LMIC.txChnl == /* NUM_DEFAULT_CHANNELS */ nDefaultChannels)
LMIC.txChnl = 0;
if ((++LMIC.txCnt % nDefaultChannels) == 0) {
// Lower DR every nth try (having all default channels with same DR)
//
// TODO(tmm@mcci.com) add new DR_REGIN_JOIN_MIN instead of LORAWAN_DR0;
// then we can eliminate the LMIC_REGION_as923 below because we'll set
// the failed flag here. This will cause the outer caller to take the
// appropriate join path. Or add new LMICeulike_GetLowestJoinDR()
//
if (LMIC.datarate == LORAWAN_DR0)
failed = 1; // we have tried all DR - signal EV_JOIN_FAILED
else
{
// TODO(tmm@mcci.com) - see above; please remove regional dependency from this file.
#if CFG_region != LMIC_REGION_as923
LMICcore_setDrJoin(DRCHG_NOJACC, decDR((dr_t)LMIC.datarate));
#else
// in the join of AS923 v1.1 or older, only DR2 is used.
// no need to change the DR.
LMIC.datarate = AS923_DR_SF10;
#endif
}
}
// Clear NEXTCHNL because join state engine controls channel hopping
LMIC.opmode &= ~OP_NEXTCHNL;
// Move txend to randomize synchronized concurrent joins.
// Duty cycle is based on txend.
ostime_t const time = LMICbandplan_nextJoinTime(os_getTime());
// TODO(tmm@mcci.com): change delay to (0:1) secs + a known t0, but randomized;
// starting adding a bias after 1 hour, 25 hours, etc.; and limit the duty
// cycle on power up. For testability, add a way to set the join start time
// externally (a test API) so we can check this feature.
// See https://github.com/mcci-catena/arduino-lmic/issues/2
// Current code doesn't match LoRaWAN 1.0.2 requirements.
LMIC.txend = time +
(isTESTMODE()
// Avoid collision with JOIN ACCEPT @ SF12 being sent by GW (but we missed it)
? DNW2_SAFETY_ZONE
// Otherwise: randomize join (street lamp case):
// SF12:255, SF11:127, .., SF7:8secs
//
: DNW2_SAFETY_ZONE + LMICcore_rndDelay(255 >> LMIC.datarate));
// 1 - triggers EV_JOIN_FAILED event
return failed;
}
#endif // !DISABLE_JOIN
#endif // CFG_LMIC_EU_like

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lmic_eu_like_h_
# define _lmic_eu_like_h_
#ifndef _lmic_h_
# include "lmic.h"
#endif
// make sure we want US-like code
#if !CFG_LMIC_EU_like
# error "lmic not configured for EU-like bandplan"
#endif
// TODO(tmm@mcci.com): this should come from the lmic.h or lorabase.h file; and
// it's probably affected by the fix to this issue:
// https://github.com/mcci-catena/arduino-lmic/issues/2
#define DNW2_SAFETY_ZONE ms2osticks(3000)
// provide a default for LMICbandplan_isValidBeacon1()
static inline int
LMICeulike_isValidBeacon1(const uint8_t *d) {
return os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d, OFF_BCN_CRC1);
}
#define LMICbandplan_isValidBeacon1(pFrame) LMICeulike_isValidBeacon1(pFrame)
// provide a default for LMICbandplan_isFSK()
#define LMICbandplan_isFSK() (0)
// provide a default LMICbandplan_txDoneDoFSK()
#define LMICbandplan_txDoneFSK(delay, func) do { } while (0)
#define LMICbandplan_joinAcceptChannelClear() LMICbandplan_initDefaultChannels(/* normal, not join */ 0)
enum { BAND_MILLI = 0, BAND_CENTI = 1, BAND_DECI = 2, BAND_AUX = 3 };
// there's a CFList on joins for EU-like plans
#define LMICbandplan_hasJoinCFlist() (1)
#define LMICbandplan_advanceBeaconChannel() \
do { /* nothing */ } while (0)
#define LMICbandplan_resetDefaultChannels() \
do { /* nothing */ } while (0)
#define LMICbandplan_setSessionInitDefaultChannels() \
do { LMICbandplan_initDefaultChannels(/* normal, not join */ 0); } while (0)
u1_t LMICeulike_mapChannels(u1_t chpage, u2_t chmap);
#define LMICbandplan_mapChannels(c, m) LMICeulike_mapChannels(c, m)
void LMICeulike_initJoinLoop(u1_t nDefaultChannels, s1_t adrTxPow);
#define LMICbandplan_setRx1Params() \
do { /*LMIC.freq/rps remain unchanged*/ } while (0)
void LMICeulike_updateTx(ostime_t txbeg);
#define LMICbandplan_updateTx(t) LMICeulike_updateTx(t)
ostime_t LMICeulike_nextJoinState(uint8_t nDefaultChannels);
static inline ostime_t LMICeulike_nextJoinTime(ostime_t now) {
return now;
}
#define LMICbandplan_nextJoinTime(now) LMICeulike_nextJoinTime(now)
#define LMICbandplan_init() \
do { /* nothing */ } while (0)
#endif // _lmic_eu_like_h_

View File

@ -0,0 +1,205 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic_bandplan.h"
#if defined(CFG_in866)
// ================================================================================
//
// BEG: IN866 related stuff
//
CONST_TABLE(u1_t, _DR2RPS_CRC)[] = {
ILLEGAL_RPS,
(u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0), // [0]
(u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0), // [1]
(u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [2]
(u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0), // [3]
(u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0), // [4]
(u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0), // [5]
ILLEGAL_RPS, // [6]
(u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0), // [7]
ILLEGAL_RPS
};
static CONST_TABLE(u1_t, maxFrameLens)[] = { 59+5,59+5,59+5,123+5, 230+5, 230+5 };
uint8_t LMICin866_maxFrameLen(uint8_t dr) {
if (dr < LENOF_TABLE(maxFrameLens))
return TABLE_GET_U1(maxFrameLens, dr);
else
return 0xFF;
}
static CONST_TABLE(s1_t, TXPOWLEVELS)[] = {
20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0
};
int8_t LMICin866_pow2dBm(uint8_t mcmd_ladr_p1) {
return TABLE_GET_S1(TXPOWLEVELS, (mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT);
}
// only used in this module, but used by variant macro dr2hsym().
static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = {
us2osticksRound(128 << 7), // DR_SF12
us2osticksRound(128 << 6), // DR_SF11
us2osticksRound(128 << 5), // DR_SF10
us2osticksRound(128 << 4), // DR_SF9
us2osticksRound(128 << 3), // DR_SF8
us2osticksRound(128 << 2), // DR_SF7
us2osticksRound(128 << 1), // --
us2osticksRound(80) // FSK -- not used (time for 1/2 byte)
};
ostime_t LMICin866_dr2hsym(uint8_t dr) {
return TABLE_GET_OSTIME(DR2HSYM_osticks, dr);
}
// All frequencies are marked as BAND_MILLI, and we don't do duty-cycle. But this lets
// us reuse code.
enum { NUM_DEFAULT_CHANNELS = 3 };
static CONST_TABLE(u4_t, iniChannelFreq)[NUM_DEFAULT_CHANNELS] = {
// Default operational frequencies
IN866_F1 | BAND_MILLI,
IN866_F2 | BAND_MILLI,
IN866_F3 | BAND_MILLI,
};
// india ignores join, becuase the channel setup is the same either way.
void LMICin866_initDefaultChannels(bit_t join) {
os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq));
os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap));
os_clearMem(&LMIC.bands, sizeof(LMIC.bands));
LMIC.channelMap = (1 << NUM_DEFAULT_CHANNELS) - 1;
for (u1_t fu = 0; fu<NUM_DEFAULT_CHANNELS; fu++) {
LMIC.channelFreq[fu] = TABLE_GET_U4(iniChannelFreq, fu);
LMIC.channelDrMap[fu] = DR_RANGE_MAP(IN866_DR_SF12, IN866_DR_SF7);
}
LMIC.bands[BAND_MILLI].txcap = 1; // no limit, in effect.
LMIC.bands[BAND_MILLI].txpow = IN866_TX_EIRP_MAX_DBM;
LMIC.bands[BAND_MILLI].lastchnl = os_getRndU1() % MAX_CHANNELS;
LMIC.bands[BAND_MILLI].avail = os_getTime();
}
bit_t LMIC_setupBand(u1_t bandidx, s1_t txpow, u2_t txcap) {
if (bandidx > BAND_MILLI) return 0;
//band_t* b = &LMIC.bands[bandidx];
xref2band_t b = &LMIC.bands[bandidx];
b->txpow = txpow;
b->txcap = txcap;
b->avail = os_getTime();
b->lastchnl = os_getRndU1() % MAX_CHANNELS;
return 1;
}
bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
if (chidx >= MAX_CHANNELS)
return 0;
if (band == -1) {
freq |= BAND_MILLI;
} else {
if (band > BAND_MILLI) return 0;
freq = (freq&~3) | band;
}
LMIC.channelFreq[chidx] = freq;
LMIC.channelDrMap[chidx] = drmap == 0 ? DR_RANGE_MAP(IN866_DR_SF12, IN866_DR_SF7) : drmap;
LMIC.channelMap |= 1 << chidx; // enabled right away
return 1;
}
u4_t LMICin866_convFreq(xref2cu1_t ptr) {
u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100;
if (freq < IN866_FREQ_MIN || freq > IN866_FREQ_MAX)
freq = 0;
return freq;
}
// return the next time, but also do channel hopping here
// since there's no duty cycle limitation, and no dwell limitation,
// we simply loop through the channels sequentially.
ostime_t LMICin866_nextTx(ostime_t now) {
const u1_t band = BAND_MILLI;
for (u1_t ci = 0; ci < MAX_CHANNELS; ci++) {
// Find next channel in given band
u1_t chnl = LMIC.bands[band].lastchnl;
for (u1_t ci = 0; ci<MAX_CHANNELS; ci++) {
if ((chnl = (chnl + 1)) >= MAX_CHANNELS)
chnl -= MAX_CHANNELS;
if ((LMIC.channelMap & (1 << chnl)) != 0 && // channel enabled
(LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) != 0 &&
band == (LMIC.channelFreq[chnl] & 0x3)) { // in selected band
LMIC.txChnl = LMIC.bands[band].lastchnl = chnl;
return now;
}
}
}
// no enabled channel found! just use the last channel.
return now;
}
#if !defined(DISABLE_BEACONS)
void LMICin866_setBcnRxParams(void) {
LMIC.dataLen = 0;
LMIC.freq = LMIC.channelFreq[LMIC.bcnChnl] & ~(u4_t)3;
LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN);
}
#endif // !DISABLE_BEACONS
#if !defined(DISABLE_JOIN)
ostime_t LMICin866_nextJoinState(void) {
return LMICeulike_nextJoinState(NUM_DEFAULT_CHANNELS);
}
#endif // !DISABLE_JOIN
// txDone handling for FSK.
void
LMICin866_txDoneFSK(ostime_t delay, osjobcb_t func) {
LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160);
LMIC.rxsyms = RXLEN_FSK;
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
}
void
LMICin866_initJoinLoop(void) {
LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ IN866_TX_EIRP_MAX_DBM);
}
//
// END: IN866 related stuff
//
// ================================================================================
#endif

View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic_bandplan.h"
#if defined(CFG_us915)
// ================================================================================
//
// BEG: US915 related stuff
//
CONST_TABLE(u1_t, _DR2RPS_CRC)[] = {
ILLEGAL_RPS, // [-1]
MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [0]
MAKERPS(SF9 , BW125, CR_4_5, 0, 0), // [1]
MAKERPS(SF8 , BW125, CR_4_5, 0, 0), // [2]
MAKERPS(SF7 , BW125, CR_4_5, 0, 0), // [3]
MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [4]
ILLEGAL_RPS , // [5]
ILLEGAL_RPS , // [6]
ILLEGAL_RPS , // [7]
MAKERPS(SF12, BW500, CR_4_5, 0, 0), // [8]
MAKERPS(SF11, BW500, CR_4_5, 0, 0), // [9]
MAKERPS(SF10, BW500, CR_4_5, 0, 0), // [10]
MAKERPS(SF9 , BW500, CR_4_5, 0, 0), // [11]
MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [12]
MAKERPS(SF7 , BW500, CR_4_5, 0, 0), // [13]
ILLEGAL_RPS // [14]
};
static CONST_TABLE(u1_t, maxFrameLens)[] = { 24,66,142,255,255,255,255,255, 66,142 };
uint8_t LMICus915_maxFrameLen(uint8_t dr) {
if (dr < LENOF_TABLE(maxFrameLens))
return TABLE_GET_U1(maxFrameLens, dr);
else
return 0xFF;
}
static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = {
us2osticksRound(128 << 5), // DR_SF10 DR_SF12CR
us2osticksRound(128 << 4), // DR_SF9 DR_SF11CR
us2osticksRound(128 << 3), // DR_SF8 DR_SF10CR
us2osticksRound(128 << 2), // DR_SF7 DR_SF9CR
us2osticksRound(128 << 1), // DR_SF8C DR_SF8CR
us2osticksRound(128 << 0) // ------ DR_SF7CR
};
ostime_t LMICus915_dr2hsym(uint8_t dr) {
return TABLE_GET_OSTIME(DR2HSYM_osticks, (dr) & 7); // map DR_SFnCR -> 0-6
}
u4_t LMICus915_convFreq(xref2cu1_t ptr) {
u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100;
if (freq < US915_FREQ_MIN || freq > US915_FREQ_MAX)
freq = 0;
return freq;
}
bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
if (chidx < 72 || chidx >= 72 + MAX_XCHANNELS)
return 0; // channels 0..71 are hardwired
LMIC.xchFreq[chidx - 72] = freq;
// TODO(tmm@mcci.com): don't use US SF directly, use something from the LMIC context or a static const
LMIC.xchDrMap[chidx - 72] = drmap == 0 ? DR_RANGE_MAP(US915_DR_SF10, US915_DR_SF8C) : drmap;
LMIC.channelMap[chidx >> 4] |= (1 << (chidx & 0xF));
return 1;
}
void LMIC_disableChannel(u1_t channel) {
if (channel < 72 + MAX_XCHANNELS) {
if (ENABLED_CHANNEL(channel)) {
if (IS_CHANNEL_125khz(channel))
LMIC.activeChannels125khz--;
else if (IS_CHANNEL_500khz(channel))
LMIC.activeChannels500khz--;
}
LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF));
}
}
void LMIC_enableChannel(u1_t channel) {
if (channel < 72 + MAX_XCHANNELS) {
if (!ENABLED_CHANNEL(channel)) {
if (IS_CHANNEL_125khz(channel))
LMIC.activeChannels125khz++;
else if (IS_CHANNEL_500khz(channel))
LMIC.activeChannels500khz++;
}
LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF));
}
}
void LMIC_enableSubBand(u1_t band) {
ASSERT(band < 8);
u1_t start = band * 8;
u1_t end = start + 8;
// enable all eight 125 kHz channels in this subband
for (int channel = start; channel < end; ++channel)
LMIC_enableChannel(channel);
// there's a single 500 kHz channel associated with
// each group of 8 125 kHz channels. Enable it, too.
LMIC_enableChannel(64 + band);
}
void LMIC_disableSubBand(u1_t band) {
ASSERT(band < 8);
u1_t start = band * 8;
u1_t end = start + 8;
// disable all eight 125 kHz channels in this subband
for (int channel = start; channel < end; ++channel)
LMIC_disableChannel(channel);
// there's a single 500 kHz channel associated with
// each group of 8 125 kHz channels. Disable it, too.
LMIC_disableChannel(64 + band);
}
void LMIC_selectSubBand(u1_t band) {
ASSERT(band < 8);
for (int b = 0; b<8; ++b) {
if (band == b)
LMIC_enableSubBand(b);
else
LMIC_disableSubBand(b);
}
}
void LMICus915_updateTx(ostime_t txbeg) {
u1_t chnl = LMIC.txChnl;
if (chnl < 64) {
LMIC.freq = US915_125kHz_UPFBASE + chnl*US915_125kHz_UPFSTEP;
if (LMIC.activeChannels125khz >= 50)
LMIC.txpow = 30;
else
LMIC.txpow = 21;
} else {
// at 500kHz bandwidth, we're allowed more power.
LMIC.txpow = 26;
if (chnl < 64 + 8) {
LMIC.freq = US915_500kHz_UPFBASE + (chnl - 64)*US915_500kHz_UPFSTEP;
}
else {
ASSERT(chnl < 64 + 8 + MAX_XCHANNELS);
LMIC.freq = LMIC.xchFreq[chnl - 72];
}
}
// Update global duty cycle stats
if (LMIC.globalDutyRate != 0) {
ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate);
}
}
#if !defined(DISABLE_BEACONS)
void LMICus915_setBcnRxParams(void) {
LMIC.dataLen = 0;
LMIC.freq = US915_500kHz_DNFBASE + LMIC.bcnChnl * US915_500kHz_DNFSTEP;
LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN);
}
#endif // !DISABLE_BEACONS
// TODO(tmm@mcci.com): parmeterize for US-like
void LMICus915_setRx1Params(void) {
LMIC.freq = US915_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * US915_500kHz_DNFSTEP;
if( /* TX datarate */LMIC.dndr < US915_DR_SF8C )
LMIC.dndr += US915_DR_SF10CR - US915_DR_SF10;
else if( LMIC.dndr == US915_DR_SF8C )
LMIC.dndr = US915_DR_SF7CR;
LMIC.rps = dndr2rps(LMIC.dndr);
}
//
// END: US915 related stuff
//
// ================================================================================
#endif

View File

@ -0,0 +1,257 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic_bandplan.h"
#if CFG_LMIC_US_like
#ifndef LMICuslike_getFirst500kHzDR
# error "LMICuslike_getFirst500kHzDR() not defined by bandplan"
#endif
static void setNextChannel(uint start, uint end, uint count) {
ASSERT(count>0);
ASSERT(start<end);
ASSERT(count <= (end - start));
// We used to pick a random channel once and then just increment. That is not per spec.
// Now we use a new random number each time, because they are not very expensive.
// Regarding the algo below, we cannot pick a number and scan until we hit an enabled channel.
// That would result in the first enabled channel following a set of disabled ones
// being used more frequently than the other enabled channels.
// Last used channel is in range. It is not a candidate, per spec.
uint lastTxChan = LMIC.txChnl;
if (start <= lastTxChan && lastTxChan<end &&
// Adjust count only if still enabled. Otherwise, no chance of selection.
ENABLED_CHANNEL(lastTxChan)) {
--count;
if (count == 0) {
return; // Only one active channel, so keep using it.
}
}
uint nth = os_getRndU1() % count;
for (u1_t chnl = start; chnl<end; chnl++) {
// Scan for nth enabled channel that is not the last channel used
if (chnl != lastTxChan && ENABLED_CHANNEL(chnl) && (nth--) == 0) {
LMIC.txChnl = chnl;
return;
}
}
// No feasible channel found! Keep old one.
}
bit_t LMIC_setupBand(u1_t bandidx, s1_t txpow, u2_t txcap) {
// nothing; just succeed.
return 1;
}
void LMICuslike_initDefaultChannels(bit_t fJoin) {
// things work the same for join as normal.
for (u1_t i = 0; i<4; i++)
LMIC.channelMap[i] = 0xFFFF;
LMIC.channelMap[4] = 0x00FF;
LMIC.activeChannels125khz = 64;
LMIC.activeChannels500khz = 8;
}
u1_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap) {
/*
|| MCMD_LADR_CHP_125ON and MCMD_LADR_CHP_125OFF are special. The
|| channel map appllies to 500kHz (ch 64..71) and in addition
|| all channels 0..63 are turned off or on. MCMC_LADR_CHP_BANK
|| is also special, in that it enables subbands.
*/
u1_t base, top;
if (chpage < MCMD_LADR_CHP_USLIKE_SPECIAL) {
// operate on channels 0..15, 16..31, 32..47, 48..63
base = chpage << 4;
top = base + 16;
if (base == 64) {
if (chmap & 0xFF00) {
// those are reserved bits, fail.
return 0;
}
top = 72;
}
} else if (chpage == MCMD_LADR_CHP_BANK) {
if (chmap & 0xFF00) {
// those are resreved bits, fail.
return 0;
}
// each bit enables a bank of channels
for (u1_t subband = 0; subband < 8; ++subband, chmap >>= 1) {
if (chmap & 1) {
LMIC_enableSubBand(subband);
} else {
LMIC_disableSubBand(subband);
}
// don't change any channels below
base = top = 0;
}
} else if (chpage == MCMD_LADR_CHP_125ON || chpage == MCMD_LADR_CHP_125OFF) {
u1_t const en125 = chpage == MCMD_LADR_CHP_125ON;
// enable or disable all 125kHz channels
for (u1_t chnl = 0; chnl < 64; ++chnl) {
if (en125)
LMIC_enableChannel(chnl);
else
LMIC_disableChannel(chnl);
}
// then apply mask to top 8 channels.
base = 64;
top = 72;
} else {
return 0;
}
// apply chmap to channels in [base..top-1].
// Use enable/disable channel to keep activeChannel counts in sync.
for (u1_t chnl = base; chnl < top; ++chnl, chmap >>= 1) {
if (chmap & 0x0001)
LMIC_enableChannel(chnl);
else
LMIC_disableChannel(chnl);
}
return 1;
}
// US does not have duty cycling - return now as earliest TX time
// but also do the channel hopping dance.
ostime_t LMICuslike_nextTx(ostime_t now) {
// TODO(tmm@mcci.com): use a static const for US-like
if (LMIC.datarate >= LMICuslike_getFirst500kHzDR()) { // 500kHz
ASSERT(LMIC.activeChannels500khz>0);
setNextChannel(64, 64 + 8, LMIC.activeChannels500khz);
}
else { // 125kHz
ASSERT(LMIC.activeChannels125khz>0);
setNextChannel(0, 64, LMIC.activeChannels125khz);
}
return now;
}
#if !defined(DISABLE_JOIN)
void LMICuslike_initJoinLoop(void) {
// set an initial condition so that setNextChannel()'s preconds are met
LMIC.txChnl = 0;
// then chose a new channel. This gives us a random first channel for
// the join. Minor nit: if channel 0 is enabled, it will never be used
// as the first join channel. The join logic uses the current txChnl,
// then changes after the rx window expires; so we need to set a valid
// starting point.
setNextChannel(0, 64, LMIC.activeChannels125khz);
// initialize the adrTxPower.
// TODO(tmm@mcci.com): is this right for all US-like regions
LMIC.adrTxPow = 20; // dBm
ASSERT((LMIC.opmode & OP_NEXTCHNL) == 0);
// make sure LMIC.txend is valid.
LMIC.txend = os_getTime();
// make sure the datarate is set to DR0 per LoRaWAN regional reqts V1.0.2,
// section 2.2.2
// TODO(tmm@mcci.com): parameterize this for US-like
LMICcore_setDrJoin(DRCHG_SET, LORAWAN_DR0);
// TODO(tmm@mcci.com) need to implement the transmit randomization and
// duty cycle restrictions from LoRaWAN V1.0.2 section 7.
}
#endif // !DISABLE_JOIN
#if !defined(DISABLE_JOIN)
//
// TODO(tmm@mcci.com):
//
// The definition of this is a little strange. this seems to return a time, but
// in reality it returns 0 if the caller should continue scanning through
// channels, and 1 if the caller has scanned all channels on this session,
// and therefore should reset to the beginning. The IBM 1.6 code is the
// same way, so apparently I just carried this across. We should declare
// as bool_t and change callers to use the result clearly as a flag.
//
ostime_t LMICuslike_nextJoinState(void) {
// Try the following:
// DR0 (SF10) on a random channel 0..63
// (honoring enable mask)
// DR4 (SF8C) on a random 500 kHz channel 64..71
// (always determined by
// previously selected
// 125 kHz channel)
//
u1_t failed = 0;
// TODO(tmm@mcci.com) parameterize for US-like
if (LMIC.datarate != LMICuslike_getFirst500kHzDR()) {
// assume that 500 kHz equiv of last 125 kHz channel
// is also enabled, and use it next.
LMIC.txChnl = 64 + (LMIC.txChnl >> 3);
LMICcore_setDrJoin(DRCHG_SET, LMICuslike_getFirst500kHzDR());
}
else {
setNextChannel(0, 64, LMIC.activeChannels125khz);
// TODO(tmm@mcci.com) parameterize
s1_t dr = LORAWAN_DR0;
if ((++LMIC.txCnt & 0x7) == 0) {
failed = 1; // All DR exhausted - signal failed
}
LMICcore_setDrJoin(DRCHG_SET, dr);
}
LMIC.opmode &= ~OP_NEXTCHNL;
// TODO(tmm@mcci.com): change delay to (0:1) secs + a known t0, but randomized;
// starting adding a bias after 1 hour, 25 hours, etc.; and limit the duty
// cycle on power up. For testability, add a way to set the join start time
// externally (a test API) so we can check this feature.
// See https://github.com/mcci-catena/arduino-lmic/issues/2
// Current code doesn't match LoRaWAN 1.0.2 requirements.
LMIC.txend = os_getTime() +
(isTESTMODE()
// Avoid collision with JOIN ACCEPT being sent by GW (but we missed it - GW is still busy)
? DNW2_SAFETY_ZONE
// Otherwise: randomize join (street lamp case):
// SF10:16, SF9=8,..SF8C:1secs
: LMICcore_rndDelay(16 >> LMIC.datarate));
// 1 - triggers EV_JOIN_FAILED event
return failed;
}
#endif
#endif // CFG_LMIC_US_like

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lmic_us_like_h_
# define _lmic_us_like_h_
// make sure we want US-like code
#if !CFG_LMIC_US_like
# error "lmic not configured for us-like bandplan"
#endif
// TODO(tmm@mcci.com): this should come from the lmic.h or lorabase.h file; and
// it's probably affected by the fix to this issue:
// https://github.com/mcci-catena/arduino-lmic/issues/2
#define DNW2_SAFETY_ZONE ms2osticks(750)
#define IS_CHANNEL_125khz(c) (c<64)
#define IS_CHANNEL_500khz(c) (c>=64 && c<72)
#define ENABLED_CHANNEL(chnl) ((LMIC.channelMap[(chnl >> 4)] & (1<<(chnl & 0x0F))) != 0)
// provide the isValidBeacon1 function -- int for bool.
static inline int
LMICuslike_isValidBeacon1(const uint8_t *d) {
return os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d, OFF_BCN_CRC1);
}
#define LMICbandplan_isValidBeacon1(pFrame) LMICuslike_isValidBeacon1(pFrame)
// provide a default for LMICbandplan_isFSK()
#define LMICbandplan_isFSK() (0)
// provide a default LMICbandplan_txDoneFSK()
#define LMICbandplan_txDoneFSK(delay, func) do { } while (0)
// provide a default LMICbandplan_joinAcceptChannelClear()
#define LMICbandplan_joinAcceptChannelClear() do { } while (0)
// no CFList on joins for US-like plans
#define LMICbandplan_hasJoinCFlist() (0)
#define LMICbandplan_advanceBeaconChannel() \
do { LMIC.bcnChnl = (LMIC.bcnChnl+1) & 7; } while (0)
// TODO(tmm@mcci.com): decide whether we want to do this on every
// reset or just restore the last sub-band selected by the user.
#define LMICbandplan_resetDefaultChannels() \
LMICbandplan_initDefaultChannels(/* normal */ 0)
void LMICuslike_initDefaultChannels(bit_t fJoin);
#define LMICbandplan_initDefaultChannels(fJoin) LMICuslike_initDefaultChannels(fJoin)
#define LMICbandplan_setSessionInitDefaultChannels() \
do { /* nothing */} while (0)
u1_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap);
#define LMICbandplan_mapChannels(chpage, chmap) LMICuslike_mapChannels(chpage, chmap)
ostime_t LMICuslike_nextTx(ostime_t now);
#define LMICbandplan_nextTx(now) LMICuslike_nextTx(now)
void LMICuslike_initJoinLoop(void);
#define LMICbandplan_initJoinLoop() LMICuslike_initJoinLoop()
ostime_t LMICuslike_nextJoinState(void);
#define LMICbandplan_nextJoinState() LMICuslike_nextJoinState();
static inline ostime_t LMICeulike_nextJoinTime(ostime_t now) {
return now;
}
#define LMICbandplan_nextJoinTime(now) LMICeulike_nextJoinTime(now)
#define LMICbandplan_init() \
do { /* nothing */ } while (0)
#endif // _lmic_us_like_h_

View File

@ -0,0 +1,335 @@
/*
Module: lmic_util.c
Function:
Encoding and decoding utilities for LMIC clients.
Copyright & License:
See accompanying LICENSE file.
Author:
Terry Moore, MCCI September 2019
*/
#include "lmic_util.h"
#include <math.h>
/*
Name: LMIC_f2sflt16()
Function:
Encode a floating point number into a uint16_t.
Definition:
uint16_t LMIC_f2sflt16(
float f
);
Description:
The float to be transmitted must be a number in the range (-1.0, 1.0).
It is converted to 16-bit integer formatted as follows:
bits 15: sign
bits 14..11: biased exponent
bits 10..0: mantissa
The float is properly rounded, and saturates.
Note that the encoded value is sign/magnitude format, rather than
two's complement for negative values.
Returns:
0xFFFF for negative values <= 1.0;
0x7FFF for positive values >= 1.0;
Otherwise an appropriate float.
*/
uint16_t
LMIC_f2sflt16(
float f
)
{
if (f <= -1.0)
return 0xFFFF;
else if (f >= 1.0)
return 0x7FFF;
else
{
int iExp;
float normalValue;
uint16_t sign;
normalValue = frexpf(f, &iExp);
sign = 0;
if (normalValue < 0)
{
// set the "sign bit" of the result
// and work with the absolute value of normalValue.
sign = 0x8000;
normalValue = -normalValue;
}
// abs(f) is supposed to be in [0..1), so useful exp
// is [0..-15]
iExp += 15;
if (iExp < 0)
iExp = 0;
// bit 15 is the sign
// bits 14..11 are the exponent
// bits 10..0 are the fraction
// we conmpute the fraction and then decide if we need to round.
uint16_t outputFraction = ldexpf(normalValue, 11) + 0.5;
if (outputFraction >= (1 << 11u))
{
// reduce output fraction
outputFraction = 1 << 10;
// increase exponent
++iExp;
}
// check for overflow and return max instead.
if (iExp > 15)
return 0x7FFF | sign;
return (uint16_t)(sign | (iExp << 11u) | outputFraction);
}
}
/*
Name: LMIC_f2sflt12()
Function:
Encode a floating point number into a uint16_t using only 12 bits.
Definition:
uint16_t LMIC_f2sflt16(
float f
);
Description:
The float to be transmitted must be a number in the range (-1.0, 1.0).
It is converted to 16-bit integer formatted as follows:
bits 15-12: zero
bit 11: sign
bits 10..7: biased exponent
bits 6..0: mantissa
The float is properly rounded, and saturates.
Note that the encoded value is sign/magnitude format, rather than
two's complement for negative values.
Returns:
0xFFF for negative values <= 1.0;
0x7FF for positive values >= 1.0;
Otherwise an appropriate float.
*/
uint16_t
LMIC_f2sflt12(
float f
)
{
if (f <= -1.0)
return 0xFFF;
else if (f >= 1.0)
return 0x7FF;
else
{
int iExp;
float normalValue;
uint16_t sign;
normalValue = frexpf(f, &iExp);
sign = 0;
if (normalValue < 0)
{
// set the "sign bit" of the result
// and work with the absolute value of normalValue.
sign = 0x800;
normalValue = -normalValue;
}
// abs(f) is supposed to be in [0..1), so useful exp
// is [0..-15]
iExp += 15;
if (iExp < 0)
iExp = 0;
// bit 15 is the sign
// bits 14..11 are the exponent
// bits 10..0 are the fraction
// we conmpute the fraction and then decide if we need to round.
uint16_t outputFraction = ldexpf(normalValue, 7) + 0.5;
if (outputFraction >= (1 << 7u))
{
// reduce output fraction
outputFraction = 1 << 6;
// increase exponent
++iExp;
}
// check for overflow and return max instead.
if (iExp > 15)
return 0x7FF | sign;
return (uint16_t)(sign | (iExp << 7u) | outputFraction);
}
}
/*
Name: LMIC_f2uflt16()
Function:
Encode a floating point number into a uint16_t.
Definition:
uint16_t LMIC_f2uflt16(
float f
);
Description:
The float to be transmitted must be a number in the range [0, 1.0).
It is converted to 16-bit integer formatted as follows:
bits 15..12: biased exponent
bits 11..0: mantissa
The float is properly rounded, and saturates.
Note that the encoded value is sign/magnitude format, rather than
two's complement for negative values.
Returns:
0x0000 for values < 0.0;
0xFFFF for positive values >= 1.0;
Otherwise an appropriate encoding of the input float.
*/
uint16_t
LMIC_f2uflt16(
float f
)
{
if (f < 0.0)
return 0;
else if (f >= 1.0)
return 0xFFFF;
else
{
int iExp;
float normalValue;
normalValue = frexpf(f, &iExp);
// f is supposed to be in [0..1), so useful exp
// is [0..-15]
iExp += 15;
if (iExp < 0)
// underflow.
iExp = 0;
// bits 15..12 are the exponent
// bits 11..0 are the fraction
// we conmpute the fraction and then decide if we need to round.
uint16_t outputFraction = ldexpf(normalValue, 12) + 0.5;
if (outputFraction >= (1 << 12u))
{
// reduce output fraction
outputFraction = 1 << 11;
// increase exponent
++iExp;
}
// check for overflow and return max instead.
if (iExp > 15)
return 0xFFFF;
return (uint16_t)((iExp << 12u) | outputFraction);
}
}
/*
Name: LMIC_f2uflt12()
Function:
Encode positive floating point number into a uint16_t using only 12 bits.
Definition:
uint16_t LMIC_f2sflt16(
float f
);
Description:
The float to be transmitted must be a number in the range [0, 1.0).
It is converted to 16-bit integer formatted as follows:
bits 15-12: zero
bits 11..8: biased exponent
bits 7..0: mantissa
The float is properly rounded, and saturates.
Returns:
0x000 for negative values < 0.0;
0xFFF for positive values >= 1.0;
Otherwise an appropriate float.
*/
uint16_t
LMIC_f2uflt12(
float f
)
{
if (f < 0.0)
return 0x000;
else if (f >= 1.0)
return 0xFFF;
else
{
int iExp;
float normalValue;
normalValue = frexpf(f, &iExp);
// f is supposed to be in [0..1), so useful exp
// is [0..-15]
iExp += 15;
if (iExp < 0)
// graceful underflow
iExp = 0;
// bits 11..8 are the exponent
// bits 7..0 are the fraction
// we conmpute the fraction and then decide if we need to round.
uint16_t outputFraction = ldexpf(normalValue, 8) + 0.5;
if (outputFraction >= (1 << 8u))
{
// reduce output fraction
outputFraction = 1 << 7;
// increase exponent
++iExp;
}
// check for overflow and return max instead.
if (iExp > 15)
return 0xFFF;
return (uint16_t)((iExp << 8u) | outputFraction);
}
}

View File

@ -0,0 +1,34 @@
/*
Module: lmic_util.h
Function:
Declare encoding and decoding utilities for LMIC clients.
Copyright & License:
See accompanying LICENSE file.
Author:
Terry Moore, MCCI September 2019
*/
#ifndef _LMIC_UTIL_H_
# define _LMIC_UTIL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
uint16_t LMIC_f2sflt16(float);
uint16_t LMIC_f2sflt12(float);
uint16_t LMIC_f2uflt16(float);
uint16_t LMIC_f2uflt12(float);
#ifdef __cplusplus
}
#endif
#endif /* _LMIC_UTIL_H_ */

View File

@ -0,0 +1,628 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyritght (c) 2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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 };
// 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 };
// there are exactly 16 datarates
enum _dr_code_t {
LORAWAN_DR0 = 0,
LORAWAN_DR1,
LORAWAN_DR2,
LORAWAN_DR3,
LORAWAN_DR4,
LORAWAN_DR5,
LORAWAN_DR6,
LORAWAN_DR7,
LORAWAN_DR8,
LORAWAN_DR9,
LORAWAN_DR10,
LORAWAN_DR11,
LORAWAN_DR12,
LORAWAN_DR13,
LORAWAN_DR14,
LORAWAN_DR15,
LORAWAN_DR_LENGTH // 16, for sizing arrays.
};
// post conditions from this block: symbols used by general code that is not
// ostensiblly region-specific.
// DR_DFLTMIN must be defined as a suitable substititute value if we get a bogus DR
// DR_PAGE is used only for a non-supported debug system, but should be defined.
// CHNL_DNW2 is the channel to be used for RX2
// FREQ_DNW2 is the frequency to be used for RX2
// DR_DNW2 is the data-rate to be used for RX2
//
// The Class B stuff is untested and definitely wrong in parts for LoRaWAN 1.02
// CHNL_PING is the channel to be used for pinging.
// FREQ_PING is the default ping channel frequency
// DR_PING is the data-rate to be used for pings.
// CHNL_BCN is the channel to be used for the beacon (or perhaps the start chan)
// FREQ_BCN is the frequency to be used for the beacon
// DR_BCN is the datarate to be used for the beacon
// AIRTIME_BCN is the airtime for the beacon
#if defined(CFG_eu868) // ==============================================
#include "lorabase_eu868.h"
// per 2.1.3: not implemented
#define LMIC_ENABLE_TxParamSetupReq 0
enum { DR_DFLTMIN = EU868_DR_SF7 }; // DR5
// DR_PAGE is a debugging parameter
enum { DR_PAGE = DR_PAGE_EU868 };
//enum { CHNL_PING = 5 };
enum { FREQ_PING = EU868_F6 }; // default ping freq
enum { DR_PING = EU868_DR_SF9 }; // default ping DR
//enum { CHNL_DNW2 = 5 };
enum { FREQ_DNW2 = EU868_F6 };
enum { DR_DNW2 = EU868_DR_SF12 };
enum { CHNL_BCN = 5 };
enum { FREQ_BCN = EU868_F6 };
enum { DR_BCN = EU868_DR_SF9 };
enum { AIRTIME_BCN = 144384 }; // micros
enum { LMIC_REGION_EIRP = EU868_LMIC_REGION_EIRP }; // region uses EIRP
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
};
// for backwards compatibility. This must match _dr_eu868_t
# if LMIC_DR_LEGACY
enum _dr_configured_t {
DR_SF12 = EU868_DR_SF12,
DR_SF11 = EU868_DR_SF11,
DR_SF10 = EU868_DR_SF10,
DR_SF9 = EU868_DR_SF9,
DR_SF8 = EU868_DR_SF8,
DR_SF7 = EU868_DR_SF7,
DR_SF7B = EU868_DR_SF7B,
DR_FSK = EU868_DR_FSK,
DR_NONE = EU868_DR_NONE
};
# endif // LMIC_DR_LEGACY
#elif defined(CFG_us915) // =========================================
#include "lorabase_us915.h"
// per 2.2.3: not implemented
#define LMIC_ENABLE_TxParamSetupReq 0
enum { DR_DFLTMIN = US915_DR_SF7 }; // DR5
// DR_PAGE is a debugging parameter; it must be defined but it has no use in arduino-lmic
enum { DR_PAGE = DR_PAGE_US915 };
//enum { CHNL_PING = 0 }; // used only for default init of state (follows beacon - rotating)
enum { FREQ_PING = US915_500kHz_DNFBASE + 0*US915_500kHz_DNFSTEP }; // default ping freq
enum { DR_PING = US915_DR_SF10CR }; // default ping DR
//enum { CHNL_DNW2 = 0 };
enum { FREQ_DNW2 = US915_500kHz_DNFBASE + 0*US915_500kHz_DNFSTEP };
enum { DR_DNW2 = US915_DR_SF12CR };
enum { CHNL_BCN = 0 }; // used only for default init of state (rotating beacon scheme)
enum { DR_BCN = US915_DR_SF12CR };
// TODO(tmm@mcci.com): check this, as beacon DR was SF10 in IBM code.
enum { AIRTIME_BCN = 72192 }; // micros
enum { LMIC_REGION_EIRP = US915_LMIC_REGION_EIRP }; // region uses EIRP
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
};
# if LMIC_DR_LEGACY
enum _dr_configured_t {
DR_SF10 = US915_DR_SF10,
DR_SF9 = US915_DR_SF9,
DR_SF8 = US915_DR_SF8,
DR_SF7 = US915_DR_SF7,
DR_SF8C = US915_DR_SF8C,
DR_NONE = US915_DR_NONE,
DR_SF12CR = US915_DR_SF12CR,
DR_SF11CR = US915_DR_SF11CR,
DR_SF10CR = US915_DR_SF10CR,
DR_SF9CR = US915_DR_SF9CR,
DR_SF8CR = US915_DR_SF8CR,
DR_SF7CR = US915_DR_SF7CR
};
# endif // LMIC_DR_LEGACY
#elif defined(CFG_au921) // =========================================
#include "lorabase_au921.h"
// per 2.5.3: not implemented
#define LMIC_ENABLE_TxParamSetupReq 0
enum { DR_DFLTMIN = AU921_DR_SF7 }; // DR5
// DR_PAGE is a debugging parameter; it must be defined but it has no use in arduino-lmic
enum { DR_PAGE = DR_PAGE_AU921 };
//enum { CHNL_PING = 0 }; // used only for default init of state (follows beacon - rotating)
enum { FREQ_PING = AU921_500kHz_DNFBASE + 0*AU921_500kHz_DNFSTEP }; // default ping freq
enum { DR_PING = AU921_DR_SF10CR }; // default ping DR
//enum { CHNL_DNW2 = 0 };
enum { FREQ_DNW2 = AU921_500kHz_DNFBASE + 0*AU921_500kHz_DNFSTEP };
enum { DR_DNW2 = AU921_DR_SF12CR }; // DR8
enum { CHNL_BCN = 0 }; // used only for default init of state (rotating beacon scheme)
enum { DR_BCN = AU921_DR_SF10CR };
enum { AIRTIME_BCN = 72192 }; // micros ... TODO(tmm@mcci.com) check.
enum { LMIC_REGION_EIRP = AU921_LMIC_REGION_EIRP }; // region uses EIRP
enum {
// Beacon frame format AU DR10/SF10 500kHz
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
};
# if LMIC_DR_LEGACY
enum _dr_configured_t {
DR_SF12 = AU921_DR_SF12,
DR_SF11 = AU921_DR_SF11,
DR_SF10 = AU921_DR_SF10,
DR_SF9 = AU921_DR_SF9,
DR_SF8 = AU921_DR_SF8,
DR_SF7 = AU921_DR_SF7,
DR_SF8C = AU921_DR_SF8C,
DR_NONE = AU921_DR_NONE,
DR_SF12CR = AU921_DR_SF12CR,
DR_SF11CR = AU921_DR_SF11CR,
DR_SF10CR = AU921_DR_SF10CR,
DR_SF9CR = AU921_DR_SF9CR,
DR_SF8CR = AU921_DR_SF8CR,
DR_SF7CR = AU921_DR_SF7CR
};
# endif // LMIC_DR_LEGACY
#elif defined(CFG_as923) // ==============================================
#include "lorabase_as923.h"
// per 2.7.3: must be implemented
#define LMIC_ENABLE_TxParamSetupReq 1
enum { DR_DFLTMIN = AS923_DR_SF10 }; // DR2
// DR_PAGE is a debugging parameter
enum { DR_PAGE = DR_PAGE_AS923 };
enum { FREQ_PING = AS923_F2 }; // default ping freq
enum { DR_PING = AS923_DR_SF9 }; // default ping DR: DR3
enum { FREQ_DNW2 = AS923_FDOWN };
enum { DR_DNW2 = AS923_DR_SF10 };
enum { CHNL_BCN = 5 };
enum { FREQ_BCN = AS923_FBCN };
enum { DR_BCN = AS923_DR_SF9 };
enum { AIRTIME_BCN = 144384 }; // micros
enum { LMIC_REGION_EIRP = AS923_LMIC_REGION_EIRP }; // region uses EIRP
enum {
// Beacon frame format AS SF9
OFF_BCN_NETID = 0,
OFF_BCN_TIME = 2,
OFF_BCN_CRC1 = 6,
OFF_BCN_INFO = 8,
OFF_BCN_LAT = 9,
OFF_BCN_LON = 12,
OFF_BCN_CRC2 = 15,
LEN_BCN = 17
};
# if LMIC_DR_LEGACY
enum _dr_configured_t {
DR_SF12 = AS923_DR_SF12,
DR_SF11 = AS923_DR_SF11,
DR_SF10 = AS923_DR_SF10,
DR_SF9 = AS923_DR_SF9,
DR_SF8 = AS923_DR_SF8,
DR_SF7 = AS923_DR_SF7,
DR_SF7B = AS923_DR_SF7B,
DR_FSK = AS923_DR_FSK,
DR_NONE = AS923_DR_NONE
};
# endif // LMIC_DR_LEGACY
#elif defined(CFG_in866) // ==============================================
#include "lorabase_in866.h"
// per 2.9.3: not implemented
#define LMIC_ENABLE_TxParamSetupReq 0
enum { DR_DFLTMIN = IN866_DR_SF7 }; // DR5
enum { DR_PAGE = DR_PAGE_IN866 }; // DR_PAGE is a debugging parameter
enum { FREQ_PING = IN866_FB }; // default ping freq
enum { DR_PING = IN866_DR_SF8 }; // default ping DR
enum { FREQ_DNW2 = IN866_FB };
enum { DR_DNW2 = IN866_DR_SF10 };
enum { CHNL_BCN = 5 };
enum { FREQ_BCN = IN866_FB };
enum { DR_BCN = IN866_DR_SF8 };
enum { AIRTIME_BCN = 144384 }; // micros
enum { LMIC_REGION_EIRP = IN866_LMIC_REGION_EIRP }; // region uses EIRP
enum {
// Beacon frame format IN SF9
OFF_BCN_NETID = 0,
OFF_BCN_TIME = 1,
OFF_BCN_CRC1 = 5,
OFF_BCN_INFO = 7,
OFF_BCN_LAT = 8,
OFF_BCN_LON = 11,
OFF_BCN_CRC2 = 17,
LEN_BCN = 19
};
# if LMIC_DR_LEGACY
enum _dr_configured_t {
DR_SF12 = IN866_DR_SF12, // DR0
DR_SF11 = IN866_DR_SF11, // DR1
DR_SF10 = IN866_DR_SF10, // DR2
DR_SF9 = IN866_DR_SF9, // DR3
DR_SF8 = IN866_DR_SF8, // DR4
DR_SF7 = IN866_DR_SF7, // DR5
DR_FSK = IN866_DR_FSK, // DR7
DR_NONE = IN866_DR_NONE
};
# endif // LMIC_DR_LEGACY
#else
# error Unsupported configuration setting
#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, // - LinkCheckReq : -
MCMD_LADR_ANS = 0x03, // - LinkADRAnd : u1:7-3:RFU, 3/2/1: pow/DR/Ch ACK
MCMD_DCAP_ANS = 0x04, // - DutyCycleAns : -
MCMD_DN2P_ANS = 0x05, // - RxParamSetupAns : u1:7-2:RFU 1/0:datarate/channel ack
MCMD_DEVS_ANS = 0x06, // - DevStatusAns : u1:battery 0,1-254,255=?, u1:7-6:RFU,5-0:margin(-32..31)
MCMD_SNCH_ANS = 0x07, // - NewChannelAns : u1: 7-2=RFU, 1/0:DR/freq ACK
MCMD_RXTimingSetupAns = 0x08, // : -
MCMD_TxParamSetupAns = 0x09, // : -
MCMD_DIChannelAns = 0x0A, // : u1: [7-2]:RFU 1:exists 0:OK
// 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, // LinkCheckAns : u1:margin 0-254,255=unknown margin / u1:gwcnt LinkCheckReq
MCMD_LADR_REQ = 0x03, // LinkADRReq : u1:DR/TXPow, u2:chmask, u1:chpage/repeat
MCMD_DCAP_REQ = 0x04, // DutyCycleReq : u1:255 dead [7-4]:RFU, [3-0]:cap 2^-k
MCMD_DN2P_SET = 0x05, // RXParamSetupReq : u1:7-4:RFU/3-0:datarate, u3:freq
MCMD_DEVS_REQ = 0x06, // DevStatusReq : -
MCMD_SNCH_REQ = 0x07, // NewChannelReq : u1:chidx, u3:freq, u1:DRrange
MCMD_RXTimingSetupReq = 0x08, // : u1: [7-4]:RFU [3-0]: Delay 1-15s (0 => 1)
MCMD_TxParamSetupReq = 0x09, // : u1: [7-6]:RFU [5:4]: dl dwell/ul dwell [3:0] max EIRP
MCMD_DIChannelReq = 0x0A, // : u1: channel, u3: frequency
// 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 = 0xF8, // RFU bits
MCMD_DN2P_ANS_RX1DrOffsetAck = 0x04, // 0=dr2 not allowed
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_USLIKE_SPECIAL = 0x50, // first special for us-like
MCMD_LADR_CHP_BANK = 0x50, // special: bits are banks.
MCMD_LADR_CHP_125ON = 0x60, // special channel page enable, bits applied to 64..71
MCMD_LADR_CHP_125OFF = 0x70, // special channel page: disble 125K, bits apply to 64..71
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) // TODO(tmm@mcci.com): complete refactor.
EU868_MCMD_LADR_SF12 = EU868_DR_SF12<<4,
EU868_MCMD_LADR_SF11 = EU868_DR_SF11<<4,
EU868_MCMD_LADR_SF10 = EU868_DR_SF10<<4,
EU868_MCMD_LADR_SF9 = EU868_DR_SF9 <<4,
EU868_MCMD_LADR_SF8 = EU868_DR_SF8 <<4,
EU868_MCMD_LADR_SF7 = EU868_DR_SF7 <<4,
EU868_MCMD_LADR_SF7B = EU868_DR_SF7B<<4,
EU868_MCMD_LADR_FSK = EU868_DR_FSK <<4,
EU868_MCMD_LADR_20dBm = 0,
EU868_MCMD_LADR_14dBm = 1,
EU868_MCMD_LADR_11dBm = 2,
EU868_MCMD_LADR_8dBm = 3,
EU868_MCMD_LADR_5dBm = 4,
EU868_MCMD_LADR_2dBm = 5,
#elif defined(CFG_us915)
US915_MCMD_LADR_SF10 = US915_DR_SF10<<4,
US915_MCMD_LADR_SF9 = US915_DR_SF9 <<4,
US915_MCMD_LADR_SF8 = US915_DR_SF8 <<4,
US915_MCMD_LADR_SF7 = US915_DR_SF7 <<4,
US915_MCMD_LADR_SF8C = US915_DR_SF8C<<4,
US915_MCMD_LADR_SF12CR = US915_DR_SF12CR<<4,
US915_MCMD_LADR_SF11CR = US915_DR_SF11CR<<4,
US915_MCMD_LADR_SF10CR = US915_DR_SF10CR<<4,
US915_MCMD_LADR_SF9CR = US915_DR_SF9CR<<4,
US915_MCMD_LADR_SF8CR = US915_DR_SF8CR<<4,
US915_MCMD_LADR_SF7CR = US915_DR_SF7CR<<4,
US915_MCMD_LADR_30dBm = 0,
US915_MCMD_LADR_28dBm = 1,
US915_MCMD_LADR_26dBm = 2,
US915_MCMD_LADR_24dBm = 3,
US915_MCMD_LADR_22dBm = 4,
US915_MCMD_LADR_20dBm = 5,
US915_MCMD_LADR_18dBm = 6,
US915_MCMD_LADR_16dBm = 7,
US915_MCMD_LADR_14dBm = 8,
US915_MCMD_LADR_12dBm = 9,
US915_MCMD_LADR_10dBm = 10
#endif
};
// bit fields of the TxParam request
enum {
MCMD_TxParam_RxDWELL_SHIFT = 5,
MCMD_TxParam_RxDWELL_MASK = 1 << MCMD_TxParam_RxDWELL_SHIFT,
MCMD_TxParam_TxDWELL_SHIFT = 4,
MCMD_TxParam_TxDWELL_MASK = 1 << MCMD_TxParam_TxDWELL_SHIFT,
MCMD_TxParam_MaxEIRP_SHIFT = 0,
MCMD_TxParam_MaxEIRP_MASK = 0xF << MCMD_TxParam_MaxEIRP_SHIFT,
};
// 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
// ================================================================================
// 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_

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* All rights reserved.
*
* Copyright (c) 2017 MCCI Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lorabase_as923_h_
#define _lorabase_as923_h_
#ifndef _LMIC_CONFIG_PRECONDITIONS_H_
# include "lmic_config_preconditions.h"
#endif
/****************************************************************************\
|
| Basic definitions for AS923 (always in scope)
|
\****************************************************************************/
enum _dr_as923_t {
AS923_DR_SF12 = 0,
AS923_DR_SF11,
AS923_DR_SF10,
AS923_DR_SF9,
AS923_DR_SF8,
AS923_DR_SF7,
AS923_DR_SF7B,
AS923_DR_FSK,
AS923_DR_NONE
};
// Bands:
// g1 : 1% 16dBm
// freq band datarates
enum {
AS923_F1 = 923200000, // g1 SF7-12
AS923_F2 = 923400000, // g1 SF7-12
AS923_FDOWN = 923200000, // (RX2 freq, DR2)
AS923_FBCN = 923400000, // default BCN, DR3
AS923_FPING = 923400000, // default ping, DR3
};
enum {
AS923_FREQ_MIN = 915000000,
AS923_FREQ_MAX = 928000000
};
enum {
AS923_TX_EIRP_MAX_DBM = 16 // 16 dBm
};
enum { DR_PAGE_AS923 = 0x10 * (LMIC_REGION_as923 - 1) };
enum { AS923_LMIC_REGION_EIRP = 1 }; // region uses EIRP
enum { AS923JP_LBT_US = 5000 }; // microseconds of LBT time -- 5000 ==>
// 5 ms. We use us rather than ms for
// future 128us support, and just for
// backward compatibility -- there
// is code that uses the _US constant,
// and it's awkward to break it.
enum { AS923JP_LBT_DB_MAX = -80 }; // maximum channel strength in dB; if TX
// we measure more than this, we don't tx.
// AS923 v1.1, all channels face a 1% duty cycle. So this will have to change
// in the future via a config. But this code base needs major changes for
// v1.1 in any case.
enum { AS923_V102_TX_CAP = 100 }; // v1.0.2 allows 100%
#ifndef AS923_TX_CAP
# define AS923_TX_CAP AS923_V102_TX_CAP
#endif
#endif /* _lorabase_as923_h_ */

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* All rights reserved.
*
* Copyright (c) 2017 MCCI Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lorabase_au921_h_
#define _lorabase_au921_h_
#ifndef _LMIC_CONFIG_PRECONDITIONS_H_
# include "lmic_config_preconditions.h"
#endif
/****************************************************************************\
|
| Basic definitions for AS921 (always in scope)
|
\****************************************************************************/
// Frequency plan for AU 921 MHz
enum _dr_as921_t {
AU921_DR_SF12 = 0,
AU921_DR_SF11,
AU921_DR_SF10,
AU921_DR_SF9,
AU921_DR_SF8,
AU921_DR_SF7,
AU921_DR_SF8C,
AU921_DR_NONE,
// Devices behind a router:
AU921_DR_SF12CR = 8,
AU921_DR_SF11CR,
AU921_DR_SF10CR,
AU921_DR_SF9CR,
AU921_DR_SF8CR,
AU921_DR_SF7CR
};
// Default frequency plan for AU 921MHz
enum {
AU921_125kHz_UPFBASE = 915200000,
AU921_125kHz_UPFSTEP = 200000,
AU921_500kHz_UPFBASE = 915900000,
AU921_500kHz_UPFSTEP = 1600000,
AU921_500kHz_DNFBASE = 923300000,
AU921_500kHz_DNFSTEP = 600000
};
enum {
AU921_FREQ_MIN = 915000000,
AU921_FREQ_MAX = 928000000
};
enum {
AU921_TX_EIRP_MAX_DBM = 30 // 30 dBm
};
enum { DR_PAGE_AU921 = 0x10 * (LMIC_REGION_au921 - 1) };
enum { AU921_LMIC_REGION_EIRP = 1 }; // region uses EIRP
#endif /* _lorabase_au921_h_ */

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* All rights reserved.
*
* Copyright (c) 2017 MCCI Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lorabase_eu868_h_
#define _lorabase_eu868_h_
#ifndef _LMIC_CONFIG_PRECONDITIONS_H_
# include "lmic_config_preconditions.h"
#endif
/****************************************************************************\
|
| Basic definitions for EU868 (always in scope)
|
\****************************************************************************/
//
// Default frequency plan for EU 868MHz ISM band
// data rates
// this is a little confusing: the integer values of these constants are the
// DataRates from the LoRaWAN Regional Parmaeter spec. The names are just
// convenient indications, so we can use them in the rare case that we need to
// choose a DataRate by SF and configuration, not by DR code.
enum _dr_eu868_t {
EU868_DR_SF12 = 0,
EU868_DR_SF11,
EU868_DR_SF10,
EU868_DR_SF9,
EU868_DR_SF8,
EU868_DR_SF7,
EU868_DR_SF7B,
EU868_DR_FSK,
EU868_DR_NONE
};
// 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 {
EU868_TX_EIRP_MAX_DBM = 16 // 16 dBm EIRP. So subtract 3 dBm for a 3 dBi antenna.
};
enum { EU868_LMIC_REGION_EIRP = 1 }; // region uses EIRP
enum { DR_PAGE_EU868 = 0x10 * (LMIC_REGION_eu868 - 1) };
#endif /* _lorabase_eu868_h_ */

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* All rights reserved.
*
* Copyright (c) 2017 MCCI Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lorabase_in866_h_
#define _lorabase_in866_h_
#ifndef _LMIC_CONFIG_PRECONDITIONS_H_
# include "lmic_config_preconditions.h"
#endif
/****************************************************************************\
|
| Basic definitions for IN866 (always in scope)
|
\****************************************************************************/
enum _dr_in866_t {
IN866_DR_SF12 = 0, // DR0
IN866_DR_SF11, // DR1
IN866_DR_SF10, // DR2
IN866_DR_SF9, // DR3
IN866_DR_SF8, // DR4
IN866_DR_SF7, // DR5
IN866_DR_RFU, // -
IN866_DR_FSK, // DR7
IN866_DR_NONE
};
// There is no dwell-time or duty-cycle limitation for IN
//
// max power: 30dBM
//
// freq datarates
enum {
IN866_F1 = 865062500, // SF7-12 (DR0-5)
IN866_F2 = 865402500, // SF7-12 (DR0-5)
IN866_F3 = 865985000, // SF7-12 (DR0-5)
IN866_FB = 866550000, // beacon/ping
};
enum {
IN866_FREQ_MIN = 865000000,
IN866_FREQ_MAX = 867000000
};
enum {
IN866_TX_EIRP_MAX_DBM = 30 // 30 dBm
};
enum { DR_PAGE_IN866 = 0x10 * (LMIC_REGION_in866 - 1) };
enum { IN866_LMIC_REGION_EIRP = 1 }; // region uses EIRP
#endif /* _lorabase_in866_h_ */

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* All rights reserved.
*
* Copyright (c) 2017 MCCI Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _lorabase_us915_h_
#define _lorabase_us915_h_
#ifndef _LMIC_CONFIG_PRECONDITIONS_H_
# include "lmic_config_preconditions.h"
#endif
/****************************************************************************\
|
| Basic definitions for US915 (always in scope)
|
\****************************************************************************/
// Frequency plan for US 915MHz ISM band
// data rates
enum _dr_us915_t {
US915_DR_SF10 = 0,
US915_DR_SF9,
US915_DR_SF8,
US915_DR_SF7,
US915_DR_SF8C,
US915_DR_NONE,
// Devices "behind a router" (and upper half of DR list):
US915_DR_SF12CR = 8,
US915_DR_SF11CR,
US915_DR_SF10CR,
US915_DR_SF9CR,
US915_DR_SF8CR,
US915_DR_SF7CR
};
// 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 {
US915_TX_MAX_DBM = 30 // 30 dBm (but not EIRP): assumes we're
// on an 64-channel bandplan. See code
// that computes tx power.
};
enum { DR_PAGE_US915 = 0x10 * (LMIC_REGION_us915 - 1) };
enum { US915_LMIC_REGION_EIRP = 0 }; // region doesn't use EIRP, uses tx power
#endif /* _lorabase_us915_h_ */

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2016-2017 MCCI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic.h"
extern const struct lmic_pinmap lmic_pins;
// RUNTIME STATE
static struct {
osjob_t* scheduledjobs;
osjob_t* runnablejobs;
} OS;
int os_init_ex (const void *pintable) {
memset(&OS, 0x00, sizeof(OS));
hal_init_ex(pintable);
if (! radio_init())
return 0;
LMIC_init();
return 1;
}
void os_init() {
if (os_init_ex((const void *)&lmic_pins))
return;
ASSERT(0);
}
ostime_t os_getTime () {
return hal_ticks();
}
// unlink job from queue, return if removed
static int 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();
unlinkjob(&OS.scheduledjobs, job) || unlinkjob(&OS.runnablejobs, job);
hal_enableIRQs();
}
// schedule immediately runnable job
void os_setCallback (osjob_t* job, osjobcb_t cb) {
osjob_t** pnext;
hal_disableIRQs();
// remove if job was already queued
unlinkjob(&OS.runnablejobs, 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();
}
// 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
unlinkjob(&OS.scheduledjobs, 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();
}
// execute jobs from timer and from run queue
void os_runloop () {
while(1) {
os_runloop_once();
}
}
void os_runloop_once() {
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;
} else { // nothing pending
hal_sleep(); // wake by irq (timer already restarted)
}
hal_enableIRQs();
if(j) { // run job callback
j->func(j);
}
}

View File

@ -1,13 +1,29 @@
/*******************************************************************************
* 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
/*
* Copyright (c) 2014-2016 IBM Corporation.
* All rights reserved.
*
* Contributors:
* IBM Zurich Research Lab - initial API, implementation and documentation
*******************************************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//! \file
#ifndef _oslmic_h_
@ -19,7 +35,6 @@
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C"{
@ -58,6 +73,8 @@ typedef struct rxsched_t rxsched_t;
typedef struct bcninfo_t bcninfo_t;
typedef const u1_t* xref2cu1_t;
typedef u1_t* xref2u1_t;
typedef s4_t ostime_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
@ -81,11 +98,24 @@ u1_t radio_rand1 (void);
#define DEFINE_LMIC struct lmic_t LMIC
#define DECLARE_LMIC extern struct lmic_t LMIC
void radio_init (void);
typedef struct oslmic_radio_rssi_s oslmic_radio_rssi_t;
struct oslmic_radio_rssi_s {
s2_t min_rssi;
s2_t max_rssi;
s2_t mean_rssi;
u2_t n_rssi;
};
int radio_init (void);
void radio_irq_handler (u1_t dio);
void radio_irq_handler_v2 (u1_t dio, ostime_t tref);
void os_init (void);
int os_init_ex (const void *pPinMap);
void os_runloop (void);
void os_runloop_once (void);
u1_t radio_rssi (void);
void radio_monitor_rssi(ostime_t n, oslmic_radio_rssi_t *pRssi);
//================================================================================
@ -103,8 +133,6 @@ void os_runloop_once (void);
#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))
@ -192,7 +220,7 @@ void os_wlsbf2 (xref2u1_t buf, u2_t value);
#define os_getRndU2() ((u2_t)((os_getRndU1()<<8)|os_getRndU1()))
#endif
#ifndef os_crc16
u2_t os_crc16 (xref2u1_t d, uint len);
u2_t os_crc16 (xref2cu1_t d, uint len);
#endif
#endif // !HAS_os_calls
@ -211,6 +239,9 @@ u2_t os_crc16 (xref2u1_t d, uint len);
// Helper to add a prefix to the table name
#define RESOLVE_TABLE(table) constant_table_ ## table
// get number of entries in table
#define LENOF_TABLE(table) (sizeof(RESOLVE_TABLE(table)) / sizeof(RESOLVE_TABLE(table)[0]))
// 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)
@ -246,8 +277,6 @@ u2_t os_crc16 (xref2u1_t d, uint len);
// 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]; }
@ -259,7 +288,6 @@ u2_t os_crc16 (xref2u1_t d, uint len);
// Declare a table
#define CONST_TABLE(type, name) const type RESOLVE_TABLE(name)
#define lmic_printf printf
#endif
// ======================================================================

View File

@ -1,13 +1,32 @@
/*******************************************************************************
* 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
/*
* Copyright (c) 2014-2016 IBM Corporation.
* Copyright (c) 2016-2018 MCCI Corporation.
* All rights reserved.
*
* Contributors:
* IBM Zurich Research Lab - initial API, implementation and documentation
*******************************************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LMIC_DR_LEGACY 0
#include "lmic.h"
@ -116,12 +135,8 @@
// #define RegAgcThresh2 0x45 // common
// #define RegAgcThresh3 0x46 // common
// #define RegPllHop 0x4B // common
#define RegPaDac 0x4D // 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
@ -181,7 +196,17 @@
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74
#endif
//-----------------------------------------
// Parameters for RSSI monitoring
#define SX127X_FREQ_LF_MAX 525000000 // per datasheet 6.3
// per datasheet 5.5.3:
#define SX127X_RSSI_ADJUST_LF -164 // add to rssi value to get dB (LF)
#define SX127X_RSSI_ADJUST_HF -157 // add to rssi value to get dB (HF)
// per datasheet 2.5.2 (but note that we ought to ask Semtech to confirm, because
// datasheet is unclear).
#define SX127X_RX_POWER_UP us2osticks(500) // delay this long to let the receiver power up.
// ----------------------------------------
// Constants for radio registers
@ -385,6 +410,13 @@ static void configLoraModem () {
// set ModemConfig2 (sf, AgcAutoOn=1 SymbTimeoutHi=00)
writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x04);
#if CFG_TxContinuousMode
// Only for testing
// set ModemConfig2 (sf, TxContinuousMode=1, AgcAutoOn=1 SymbTimeoutHi=00)
writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x06);
#endif
#else
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
#endif /* CFG_sx1272_radio */
@ -402,16 +434,19 @@ static void configChannel () {
static void configPower () {
#ifdef CFG_sx1276_radio
// no boost used for now
// PA_BOOST output is assumed but not 20 dBm.
s1_t pw = (s1_t)LMIC.txpow;
if(pw > 15) {
pw = 15;
if(pw > 17) {
pw = 17;
} 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)
// 0x80 forces use of PA_BOOST; but we don't
// turn on 20 dBm mode. So powers are:
// 0000 => 2dBm, 0001 => 3dBm, ... 1111 => 17dBm
// But we also enforce that the high-power mode
// is off by writing RegPaDac.
writeReg(RegPaConfig, (u1_t)(0x80|(pw - 2)));
writeReg(RegPaDac, readReg(RegPaDac)|0x4);
#elif CFG_sx1272_radio
@ -514,7 +549,7 @@ static void txlora () {
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",
LMIC_DEBUG_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)),
@ -525,7 +560,33 @@ static void txlora () {
// start transmitter (buf=LMIC.frame, len=LMIC.dataLen)
static void starttx () {
ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
u1_t const rOpMode = readReg(RegOpMode);
// originally, this code ASSERT()ed, but asserts are both bad and
// blunt instruments. If we see that we're not in sleep mode,
// force sleep (because we might have to switch modes)
if ((rOpMode & OPMODE_MASK) != OPMODE_SLEEP) {
#if LMIC_DEBUG_LEVEL > 0
LMIC_DEBUG_PRINTF("?%s: OPMODE != OPMODE_SLEEP: %#02x\n", __func__, rOpMode);
#endif
opmode(OPMODE_SLEEP);
hal_waitUntil(os_getTime() + ms2osticks(1));
}
if (LMIC.lbt_ticks > 0) {
oslmic_radio_rssi_t rssi;
radio_monitor_rssi(LMIC.lbt_ticks, &rssi);
#if LMIC_X_DEBUG_LEVEL > 0
LMIC_X_DEBUG_PRINTF("LBT rssi max:min=%d:%d %d times in %d\n", rssi.max_rssi, rssi.min_rssi, rssi.n_rssi, LMIC.lbt_ticks);
#endif
if (rssi.max_rssi >= LMIC.lbt_dbmax) {
// complete the request by scheduling the job
os_setCallback(&LMIC.osjob, LMIC.osjob.func);
return;
}
}
if(getSf(LMIC.rps) == FSK) { // FSK modem
txfsk();
} else { // LoRa modem
@ -566,7 +627,13 @@ static void rxlora (u1_t rxmode) {
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));
// XXX: use flag to switch on/off inversion
if (LMIC.noRXIQinversion) {
writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ) & ~(1<<6));
} else {
writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ)|(1<<6));
}
#endif
// set symbol timeout (for single rx)
writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms);
@ -587,18 +654,22 @@ static void rxlora (u1_t rxmode) {
if (rxmode == RXMODE_SINGLE) { // single rx
hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
opmode(OPMODE_RX_SINGLE);
#if LMIC_DEBUG_LEVEL > 0
ostime_t now = os_getTime();
LMIC_DEBUG_PRINTF("start single rx: now-rxtime: %lu\n", now - LMIC.rxtime);
#endif
} else { // continous rx (scan or rssi)
opmode(OPMODE_RX);
}
#if LMIC_DEBUG_LEVEL > 0
if (rxmode == RXMODE_RSSI) {
lmic_printf("RXMODE_RSSI\n");
LMIC_DEBUG_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",
LMIC_DEBUG_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,
@ -673,7 +744,7 @@ static void startrx (u1_t rxmode) {
}
// get random seed from wideband noise rssi
void radio_init () {
int radio_init () {
hal_disableIRQs();
// manually reset radio
@ -691,9 +762,11 @@ void radio_init () {
// some sanity checks, e.g., read version number
u1_t v = readReg(RegVersion);
#ifdef CFG_sx1276_radio
ASSERT(v == 0x12 );
if(v != 0x12 )
return 0;
#elif CFG_sx1272_radio
ASSERT(v == 0x22);
if(v != 0x22)
return 0;
#else
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
#endif
@ -731,6 +804,7 @@ void radio_init () {
opmode(OPMODE_SLEEP);
hal_enableIRQs();
return 1;
}
// return next random byte derived from seed buffer
@ -754,6 +828,82 @@ u1_t radio_rssi () {
return r;
}
// monitor rssi for specified number of ostime_t ticks, and return statistics
// This puts the radio into RX continuous mode, waits long enough for the
// oscillators to start and the PLL to lock, and then measures for the specified
// period of time. The radio is then returned to idle.
//
// RSSI returned is expressed in units of dB, and is offset according to the
// current radio setting per section 5.5.5 of Semtech 1276 datasheet.
void radio_monitor_rssi(ostime_t nTicks, oslmic_radio_rssi_t *pRssi) {
uint8_t rssiMax, rssiMin;
uint16_t rssiSum;
uint16_t rssiN;
int rssiAdjust;
ostime_t tBegin;
int notDone;
rxlora(RXMODE_SCAN);
// while we're waiting for the PLLs to spin up, determine which
// band we're in and choose the base RSSI.
if (LMIC.freq > SX127X_FREQ_LF_MAX) {
rssiAdjust = SX127X_RSSI_ADJUST_HF;
} else {
rssiAdjust = SX127X_RSSI_ADJUST_LF;
}
rssiAdjust += hal_getRssiCal();
// zero the results
rssiMax = 255;
rssiMin = 0;
rssiSum = 0;
rssiN = 0;
// wait for PLLs
hal_waitUntil(os_getTime() + SX127X_RX_POWER_UP);
// scan for the desired time.
tBegin = os_getTime();
rssiMax = 0;
/* XXX(tanupoo)
* In this loop, micros() in os_getTime() returns a past time sometimes.
* At least, it happens on Dragino LoRa Mini.
* the return value of micros() looks not to be stable in IRQ disabled.
* Once it happens, this loop never exit infinitely.
* In order to prevent it, it enables IRQ before calling os_getTime(),
* disable IRQ again after that.
*/
do {
ostime_t now;
u1_t rssiNow = readReg(LORARegRssiValue);
if (rssiMax < rssiNow)
rssiMax = rssiNow;
if (rssiNow < rssiMin)
rssiMin = rssiNow;
rssiSum += rssiNow;
++rssiN;
// TODO(tmm@mcci.com) move this to os_getTime().
hal_enableIRQs();
now = os_getTime();
hal_disableIRQs();
notDone = now - (tBegin + nTicks) < 0;
} while (notDone);
// put radio back to sleep
opmode(OPMODE_SLEEP);
// compute the results
pRssi->max_rssi = (s2_t) (rssiMax + rssiAdjust);
pRssi->min_rssi = (s2_t) (rssiMin + rssiAdjust);
pRssi->mean_rssi = (s2_t) (rssiAdjust + ((rssiSum + (rssiN >> 1)) / rssiN));
pRssi->n_rssi = rssiN;
}
static CONST_TABLE(u2_t, LORA_RXDONE_FIXUP)[] = {
[FSK] = us2osticks(0), // ( 0 ticks)
[SF7] = us2osticks(0), // ( 0 ticks)
@ -767,12 +917,27 @@ static CONST_TABLE(u2_t, LORA_RXDONE_FIXUP)[] = {
// 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();
radio_irq_handler_v2(dio, os_getTime());
}
void radio_irq_handler_v2 (u1_t dio, ostime_t now) {
#if CFG_TxContinuousMode
// clear radio IRQ flags
writeReg(LORARegIrqFlags, 0xFF);
u1_t p = readReg(LORARegFifoAddrPtr);
writeReg(LORARegFifoAddrPtr, 0x00);
u1_t s = readReg(RegOpMode);
u1_t c = readReg(LORARegModemConfig2);
opmode(OPMODE_TX);
return;
#else /* ! CFG_TxContinuousMode */
#if LMIC_DEBUG_LEVEL > 0
ostime_t const entry = now;
#endif
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
LMIC_X_DEBUG_PRINTF("IRQ=%02x\n", flags);
if( flags & IRQ_LORA_TXDONE_MASK ) {
// save exact tx time
LMIC.txend = now - us2osticks(43); // TXDONE FIXUP
@ -790,15 +955,17 @@ void radio_irq_handler (u1_t dio) {
// now read the FIFO
readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
// read rx quality parameters
//LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
LMIC.snr = ((s1_t)readReg(LORARegPktSnrValue)) / 4;
//LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63)
LMIC.rssi = readReg(LORARegPktRssiValue) - 157; // RFI_HF for 868 and 915MHZ band
if (LMIC.snr < 0)
LMIC.rssi += LMIC.snr;
LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
LMIC.rssi = readReg(LORARegPktRssiValue);
LMIC_X_DEBUG_PRINTF("RX snr=%u rssi=%d\n", LMIC.snr/4, SX127X_RSSI_ADJUST_HF + LMIC.rssi);
LMIC.rssi = LMIC.rssi - 125 + 64; // RSSI [dBm] (-196...+63)
} else if( flags & IRQ_LORA_RXTOUT_MASK ) {
// indicate timeout
LMIC.dataLen = 0;
#if LMIC_DEBUG_LEVEL > 0
ostime_t now2 = os_getTime();
LMIC_DEBUG_PRINTF("rxtimeout: entry: %lu rxtime: %lu entry-rxtime: %lu now-entry: %lu rxtime-txend: %lu\n", entry, LMIC.rxtime, entry - LMIC.rxtime, now2 - entry, LMIC.rxtime-LMIC.txend);
#endif
}
// mask all radio IRQs
writeReg(LORARegIrqFlagsMask, 0xFF);
@ -831,6 +998,7 @@ void radio_irq_handler (u1_t dio) {
opmode(OPMODE_SLEEP);
// run os job (use preset func ptr)
os_setCallback(&LMIC.osjob, LMIC.osjob.func);
#endif /* ! CFG_TxContinuousMode */
}
void os_radio (u1_t mode) {

View File

@ -8,7 +8,9 @@
[platformio]
env_default = generic
;env_default = ebox
;env_default = eboxtube
;env_default = heltec
;env_default = heltecv2
;env_default = ttgov1
;env_default = ttgov2
;env_default = ttgov21old
@ -21,13 +23,13 @@ env_default = generic
;env_default = lolin32lora
;env_default = lolin32lite
;env_default = octopus32
;env_default = ebox, heltec, ttgobeam, lopy4, lopy, ttgov21old, ttgov21new
;env_default = ebox, eboxtube, heltec, ttgobeam, lopy4, lopy, ttgov21old, ttgov21new
;
description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around.
[common]
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
release_version = 1.6.0
release_version = 1.6.51
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 0
@ -41,6 +43,8 @@ board_build.partitions = min_spiffs.csv
monitor_speed = 115200
lib_deps_all =
ArduinoJson@^5.13.1
lib_deps_lora =
; MCCI LoRaWAN LMIC library@^2.2.2
lib_deps_display =
U8g2@>=2.23.16
lib_deps_rgbled =
@ -49,11 +53,10 @@ lib_deps_gps =
TinyGPSPlus@>=1.0.2
Time@>=1.5
build_flags =
; override lora settings from LMiC library in lmic/config.h and use main.h instead
-D_lmic_config_h_
-include "src/paxcounter.conf"
-include "src/hal/${PIOENV}.h"
-include "src/paxcounter.conf"
-w
'-DARDUINO_LMIC_PROJECT_CONFIG_H=../../../src/lmic_config.h'
'-DCORE_DEBUG_LEVEL=${common.debug_level}'
'-DBINTRAY_PACKAGE="${PIOENV}"'
'-DPROGVERSION="${common.release_version}"'
@ -61,11 +64,27 @@ build_flags =
[env:ebox]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 115200
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
build_flags =
${common.build_flags}
upload_protocol = ${common.upload_protocol}
extra_scripts = ${common.extra_scripts}
monitor_speed = ${common.monitor_speed}
[env:eboxtube]
platform = ${common.platform_espressif32}
framework = arduino
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 115200
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
build_flags =
${common.build_flags}
upload_protocol = ${common.upload_protocol}
@ -80,6 +99,23 @@ board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_display}
build_flags =
${common.build_flags}
upload_protocol = ${common.upload_protocol}
extra_scripts = ${common.extra_scripts}
monitor_speed = ${common.monitor_speed}
[env:heltecv2]
platform = ${common.platform_espressif32}
framework = arduino
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_display}
build_flags =
${common.build_flags}
@ -90,11 +126,12 @@ monitor_speed = ${common.monitor_speed}
[env:ttgov1]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = ttgo-lora32-v1
board_build.partitions = ${common.board_build.partitions}
upload_speed = 115200
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_display}
build_flags =
${common.build_flags}
@ -105,11 +142,12 @@ monitor_speed = ${common.monitor_speed}
[env:ttgov2]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = ttgo-lora32-v1
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_display}
build_flags =
${common.build_flags}
@ -120,11 +158,12 @@ monitor_speed = ${common.monitor_speed}
[env:ttgov21old]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_display}
build_flags =
${common.build_flags}
@ -135,11 +174,12 @@ monitor_speed = ${common.monitor_speed}
[env:ttgov21new]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_display}
build_flags =
${common.build_flags}
@ -150,11 +190,12 @@ monitor_speed = ${common.monitor_speed}
[env:ttgobeam]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_gps}
build_flags =
${common.build_flags}
@ -166,11 +207,12 @@ monitor_speed = ${common.monitor_speed}
[env:fipy]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_rgbled}
build_flags =
${common.build_flags}
@ -181,11 +223,12 @@ monitor_speed = ${common.monitor_speed}
[env:lopy]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_rgbled}
${common.lib_deps_gps}
build_flags =
@ -197,11 +240,12 @@ monitor_speed = ${common.monitor_speed}
[env:lopy4]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_rgbled}
${common.lib_deps_gps}
build_flags =
@ -219,6 +263,7 @@ board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_rgbled}
build_flags =
${common.build_flags}
@ -234,6 +279,7 @@ board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_rgbled}
build_flags =
${common.build_flags}
@ -259,12 +305,14 @@ monitor_speed = ${common.monitor_speed}
[env:octopus32]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = featheresp32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_rgbled}
${common.lib_deps_display}
build_flags =
${common.build_flags}
upload_protocol = ${common.upload_protocol}
@ -274,11 +322,12 @@ monitor_speed = ${common.monitor_speed}
[env:generic]
platform = ${common.platform_espressif32}
framework = arduino
board = esp32dev
board = heltec_wifi_lora_32
board_build.partitions = ${common.board_build.partitions}
upload_speed = 921600
lib_deps =
${common.lib_deps_all}
${common.lib_deps_lora}
${common.lib_deps_rgbled}
${common.lib_deps_gps}
${common.lib_deps_display}

View File

@ -15,7 +15,7 @@ void doHousekeeping() {
// check if update mode trigger switch was set
if (cfg.runmode == 1)
ESP.restart();
do_reset();
// task storage debugging //
ESP_LOGD(TAG, "Wifiloop %d bytes left",
@ -60,7 +60,7 @@ void doHousekeeping() {
get_salt(); // get new salt for salting hashes
if (esp_get_minimum_free_heap_size() <= MEM_LOW) // check again
esp_restart(); // memory leak, reset device
do_reset(); // memory leak, reset device
}
} // doHousekeeping()

View File

@ -4,13 +4,19 @@
#include "globals.h"
#include <esp_spi_flash.h> // needed for reading ESP32 chip attributes
HAS_DISPLAY u8x8(OLED_RST, I2C_SCL, I2C_SDA);
HAS_DISPLAY u8x8(MY_OLED_RST, MY_OLED_SCL, MY_OLED_SDA);
// helper string for converting LoRa spread factor values
#if defined(CFG_eu868)
const char lora_datarate[] = {"1211100908077BFSNA"};
#elif defined(CFG_us915)
const char lora_datarate[] = {"100908078CNA121110090807"};
#elif defined(CFG_as923)
const char lora_datarate[] = {"1211100908077BFSNA"};
#elif defined(CFG_au921)
const char lora_datarate[] = {"1211100908078CNA1211109C8C7C"};
#elif defined(CFG_in866)
const char lora_datarate[] = {"121110090807FSNA"};
#endif
uint8_t volatile DisplayState = 0;

View File

@ -28,9 +28,9 @@ void gps_loop(void *pvParameters) {
HardwareSerial GPS_Serial(1);
GPS_Serial.begin(GPS_SERIAL);
#elif defined GPS_QUECTEL_L76
#elif defined GPS_I2C
uint8_t ret;
Wire.begin(GPS_QUECTEL_L76, 400000); // I2C connect to GPS device with 400 KHz
Wire.begin(GPS_I2C, 400000); // I2C connect to GPS device with 400 KHz
Wire.beginTransmission(GPS_ADDR);
Wire.write(0x00); // dummy write
ret = Wire.endTransmission(); // check if chip is seen on i2c bus
@ -55,7 +55,7 @@ void gps_loop(void *pvParameters) {
while (GPS_Serial.available()) {
gps.encode(GPS_Serial.read());
}
#elif defined GPS_QUECTEL_L76
#elif defined GPS_I2C
Wire.requestFrom(GPS_ADDR, 32); // caution: this is a blocking call
while (Wire.available()) {
gps.encode(Wire.read());

View File

@ -1,21 +1,26 @@
#ifndef _EBOX_H
#define _EBOX_H
#include <stdint.h>
// Hardware related definitions for ebox ESP32-bit with external connected RFM95 LoRa
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1276_radio 1
#define HAS_LED GPIO_NUM_23 // blue LED on board
#define HAS_BUTTON GPIO_NUM_0 // button "PROG" on board
#define HAS_LED (23) // blue LED on board
#define HAS_BUTTON (0) // button "PROG" on board
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST (14)
#define LORA_IO0 (26)
#define LORA_IO1 (33)
#define LORA_IO2 LMIC_UNUSED_PIN
// non arduino pin definitions
#define RST GPIO_NUM_14 // ESP32 GPIO14 (Pin14) -- SX1276 NRESET (Pin7) Reset Trigger Input
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 (Pin15) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
#define DIO2 LMIC_UNUSED_PIN // 32 ESP32 GPIO32 (Pin12) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
#endif

27
src/hal/eboxtube.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef _EBOXTUBE_H
#define _EBOXTUBE_H
#include <stdint.h>
// Hardware related definitions for ebox ESP32-bit with external connected RFM95 LoRa
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1276_radio 1
#define HAS_LED (22) // Green LED on board
#define HAS_RGB_LED (2) // WS2812B RGB LED on board
#define HAS_BUTTON (0) // button "FLASH" on board
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST (14)
#define LORA_IO0 (26)
#define LORA_IO1 (33)
#define LORA_IO2 (32)
#endif

View File

@ -1,3 +1,8 @@
#ifndef _FIPY_H
#define _FIPY_H
#include <stdint.h>
// Hardware related definitions for Pycom FiPy Board
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
@ -8,16 +13,18 @@
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
#define BOARD_HAS_PSRAM // use extra 4MB extern RAM
// Hardware pin definitions for Pycom FiPy board
#define PIN_SPI_SS GPIO_NUM_18
#define PIN_SPI_MOSI GPIO_NUM_27
#define PIN_SPI_MISO GPIO_NUM_19
#define PIN_SPI_SCK GPIO_NUM_5
#define RST LMIC_UNUSED_PIN
#define DIO0 GPIO_NUM_23 // LoRa IRQ
#define DIO1 GPIO_NUM_23 // workaround
#define DIO2 LMIC_UNUSED_PIN
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST LMIC_UNUSED_PIN
#define LORA_IO0 (23) // LoRa IRQ
#define LORA_IO1 (23) // Pin tied via diode to DIO0
#define LORA_IO2 LMIC_UNUSED_PIN
// select WIFI antenna (internal = onboard / external = u.fl socket)
#define HAS_ANTENNA_SWITCH GPIO_NUM_21 // pin for switching wifi antenna
#define WIFI_ANTENNA 0 // 0 = internal, 1 = external
#endif

View File

@ -1,3 +1,8 @@
#ifndef _GENERIC_H
#define _GENERIC_H
#include <stdint.h>
// Hardware related definitions for generic ESP32 boards
#define HAS_LORA 1 // comment out if device shall not send data via LoRa or has no LoRa
@ -13,30 +18,32 @@
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
#define HAS_LED GPIO_NUM_21 // on board LED
#define HAS_BUTTON GPIO_NUM_39 // on board button
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
#define HAS_LED (21) // on board LED
#define HAS_BUTTON (39) // on board button
#define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0
#define BOARD_HAS_PSRAM // use extra 4MB extern RAM
#define HAS_GPS 1 // use if board has GPS
#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M or 7M with default configuration
// pin definitions for SPI interface of LoRa chip
#define PIN_SPI_SS GPIO_NUM_18 // SPI Chip Select
#define PIN_SPI_MOSI GPIO_NUM_27 // SPI Data Input
#define PIN_SPI_MISO GPIO_NUM_19 // SPI Data Output
#define PIN_SPI_SCK GPIO_NUM_5 // SPI Clock
#define RST LMIC_UNUSED_PIN // LoRa Reset (if wired)
#define DIO0 GPIO_NUM_26 // LoRa IO0
#define DIO1 GPIO_NUM_32 // LoRa IO1
#define DIO2 LMIC_UNUSED_PIN // LoRa IO2 (not needed)
// Pins for I2C interface of OLED Display
#define MY_OLED_SDA (4)
#define MY_OLED_SCL (15)
#define MY_OLED_RST (16)
// pin definitions for I2C interface of OLED Display
#define OLED_RST GPIO_NUM_16 // SSD1306 RST
#define I2C_SDA GPIO_NUM_4 // SD1306 D1+D2
#define I2C_SCL GPIO_NUM_15 // SD1306 D0
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST (14)
#define LORA_IO0 (26)
#define LORA_IO1 (33)
#define LORA_IO2 LMIC_UNUSED_PIN
// I2C config for Microchip 24AA02E64 DEVEUI unique address
#define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64
#define MCP_24AA02E64_MAC_ADDRESS 0xF8 // Memory adress of unique deveui 64 bits
#endif

View File

@ -1,3 +1,8 @@
#ifndef _HELTEC_H
#define _HELTEC_H
#include <stdint.h>
// Hardware related definitions for Heltec LoRa-32 Board
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
@ -5,22 +10,22 @@
#define CFG_sx1276_radio 1
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
#define HAS_LED GPIO_NUM_25 // white LED on board
#define HAS_BUTTON GPIO_NUM_0 // button "PROG" on board
#define HAS_LED (25) // white LED on board
#define HAS_BUTTON (0) // button "PROG" on board
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
// Pins for I2C interface of OLED Display
#define MY_OLED_SDA (4)
#define MY_OLED_SCL (15)
#define MY_OLED_RST (16)
// non arduino pin definitions
#define RST GPIO_NUM_14 // ESP32 GPIO14 (Pin14) -- SX1276 NRESET (Pin7) Reset Trigger Input
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 (Pin15) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
#define DIO2 LMIC_UNUSED_PIN // 32 ESP32 GPIO32 (Pin12) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST (14)
#define LORA_IO0 (26)
#define LORA_IO1 (33)
#define LORA_IO2 LMIC_UNUSED_PIN
// Hardware pin definitions for Heltec LoRa-32 Board with OLED SSD1306 I2C Display
#define OLED_RST GPIO_NUM_16 // ESP32 GPIO16 (Pin16) -- SD1306 RST
#define I2C_SDA GPIO_NUM_4 // ESP32 GPIO4 (Pin4) -- SD1306 D1+D2
#define I2C_SCL GPIO_NUM_15 // ESP32 GPIO15 (Pin15) -- SD1306 D0
#endif

View File

@ -1,3 +1,8 @@
#ifndef _HELTECV2_H
#define _HELTECV2_H
#include <stdint.h>
// Hardware related definitions for Heltec V2 LoRa-32 Board
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
@ -5,22 +10,22 @@
#define CFG_sx1276_radio 1
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
#define HAS_LED GPIO_NUM_25 // white LED on board
#define HAS_BUTTON GPIO_NUM_0 // button "PROG" on board
#define HAS_LED (25) // white LED on board
#define HAS_BUTTON (0) // button "PROG" on board
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 -- SX1276 SCK (Pin16) SPI Clock Input
// Pins for I2C interface of OLED Display
#define OLED_SDA (4)
#define OLED_SCL (15)
#define OLED_RST (16)
// non arduino pin definitions
#define RST GPIO_NUM_14 // ESP32 GPIO18 -- SX1276 NRESET (Pin7) Reset Trigger Input
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
#define DIO1 GPIO_NUM_34 // ESP32 GPIO33 -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
#define DIO2 GPIO_NUM_35 // 32 ESP32 GPIO32 -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST (14)
#define LORA_IO0 (26)
#define LORA_IO1 (34)
#define LORA_IO2 (35)
// Hardware pin definitions for Heltec LoRa-32 Board with OLED SSD1306 I2C Display
#define OLED_RST GPIO_NUM_16 // ESP32 GPIO16 -- SD1306 RST
#define I2C_SDA GPIO_NUM_4 // ESP32 GPIO4 -- SD1306 D1+D2
#define I2C_SCL GPIO_NUM_15 // ESP32 GPIO15 -- SD1306 D0
#endif

View File

@ -1,3 +1,8 @@
#ifndef _LOLINLITE_H
#define _LOLINLITE_H
#include <stdint.h>
// Hardware related definitions for lolin32lite (without LoRa shield)
#define CFG_sx1272_radio 1 // dummy
@ -6,3 +11,5 @@
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#endif

View File

@ -1,3 +1,8 @@
#ifndef _LOLINLITELORA_H
#define _LOLINLITELORA_H
#include <stdint.h>
// Hardware related definitions for lolin32 lite with loraNode32 shield
// See https://github.com/hallard/LoLin32-Lite-Lora
@ -16,24 +21,23 @@
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1276_radio 1 // RFM95 module
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS 5 // ESP32 GPIO5 (Pin5) -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI 23 // ESP32 GPIO23 (Pin23) -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK 18 // ESP32 GPIO18 (Pin18 -- SX1276 SCK (Pin16) SPI Clock Input
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST (25)
#define LORA_IO0 (27)
#define LORA_IO1 (26)
#define LORA_IO2 LMIC_UNUSED_PIN
// non arduino pin definitions
#define RST 25 // ESP32 GPIO25 (Pin25) -- SX1276 NRESET (Pin7) Reset Trigger Input
#define DIO0 27 // ESP32 GPIO27 (Pin27) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
#define DIO1 26 // ESP32 GPIO26 (Pin26) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
#define DIO2 LMIC_UNUSED_PIN // 4 ESP32 GPIO4 (Pin4) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
#define DIO5 LMIC_UNUSED_PIN // 35 ESP32 GPIO35 (Pin35) -- SX1276 DIO5 not used by LMIC for LoRa (Timeout for FSK only)
// Hardware pin definitions for LoRaNode32 Board with OLED I2C Display
#define OLED_RST U8X8_PIN_NONE // Not reset pin
#define I2C_SDA 14 // ESP32 GPIO14 (Pin14) -- OLED SDA
#define I2C_SCL 12 // ESP32 GPIO12 (Pin12) -- OLED SCL
// Pins for I2C interface of OLED Display
#define MY_OLED_SDA (14)
#define MY_OLED_SCL (12)
#define MY_OLED_RST U8X8_PIN_NONE
// I2C config for Microchip 24AA02E64 DEVEUI unique address
#define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64
#define MCP_24AA02E64_MAC_ADDRESS 0xF8 // Memory adress of unique deveui 64 bits
#endif

View File

@ -1,3 +1,8 @@
#ifndef _LOLINLORA_H
#define _LOLINLORA_H
#include <stdint.h>
// Hardware related definitions for lolin32 with loraNode32 shield
// See https://github.com/hallard/LoLin32-Lora
@ -17,24 +22,24 @@
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1276_radio 1 // RFM95 module
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS 5 // ESP32 GPIO5 (Pin5) -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI 23 // ESP32 GPIO23 (Pin23) -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK 18 // ESP32 GPIO18 (Pin18 -- SX1276 SCK (Pin16) SPI Clock Input
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST (25)
#define LORA_IO0 (27)
#define LORA_IO1 (26)
#define LORA_IO2 LMIC_UNUSED_PIN
#define LORA_IO5 LMIC_UNUSED_PIN
// non arduino pin definitions
#define RST 25 // ESP32 GPIO25 (Pin25) -- SX1276 NRESET (Pin7) Reset Trigger Input
#define DIO0 27 // ESP32 GPIO27 (Pin27) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
#define DIO1 26 // ESP32 GPIO26 (Pin26) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
#define DIO2 LMIC_UNUSED_PIN // 4 ESP32 GPIO4 (Pin4) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
#define DIO5 LMIC_UNUSED_PIN // 35 ESP32 GPIO35 (Pin35) -- SX1276 DIO5 not used by LMIC for LoRa (Timeout for FSK only)
// Hardware pin definitions for LoRaNode32 Board with OLED I2C Display
#define OLED_RST U8X8_PIN_NONE // Not reset pin
#define I2C_SDA 21 // ESP32 GPIO21 (Pin21) -- OLED SDA
#define I2C_SCL 22 // ESP32 GPIO22 (Pin22) -- OLED SCL
// Pins for I2C interface of OLED Display
#define MY_OLED_SDA (21)
#define MY_OLED_SCL (22)
#define MY_OLED_RST U8X8_PIN_NONE
// I2C config for Microchip 24AA02E64 DEVEUI unique address
#define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64
#define MCP_24AA02E64_MAC_ADDRESS 0xF8 // Memory adress of unique deveui 64 bits
#endif

View File

@ -1,35 +1,42 @@
#ifndef _LOPY_H
#define _LOPY_H
#include <stdint.h>
// Hardware related definitions for Pycom LoPy Board (NOT LoPy4)
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1272_radio 1
#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
#define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0
// Hardware pin definitions for Pycom LoPy board
#define PIN_SPI_SS GPIO_NUM_17
#define PIN_SPI_MOSI GPIO_NUM_27
#define PIN_SPI_MISO GPIO_NUM_19
#define PIN_SPI_SCK GPIO_NUM_5
#define RST GPIO_NUM_18
#define DIO0 GPIO_NUM_23 // LoRa IRQ
#define DIO1 GPIO_NUM_23 // Pin tied via diode to DIO0
#define DIO2 GPIO_NUM_23 // Pin tied via diode to DIO0
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5) // GPIO5 - SX1276 SCK
#define LORA_CS (17) // GPIO17 - SX1276 CS
#define LORA_MISO (19) // GPIO19 - SX1276 MISO
#define LORA_MOSI (27) // GPIO27 - SX1276 MOSI
#define LORA_RST (18) // GPIO18 - SX1276 RESET
#define LORA_IO0 (23) // LoRa IRQ
#define LORA_IO1 (23) // Pin tied via diode to DIO0
#define LORA_IO2 (23) // Pin tied via diode to DIO0
// select WIFI antenna (internal = onboard / external = u.fl socket)
#define HAS_ANTENNA_SWITCH GPIO_NUM_16 // pin for switching wifi antenna
#define HAS_ANTENNA_SWITCH (16) // pin for switching wifi antenna
#define WIFI_ANTENNA 0 // 0 = internal, 1 = external
// uncomment this only if your LoPy runs on a PYTRACK BOARD
//#define HAS_GPS 1
//#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21)
//#define GPS_I2C GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21)
//#define GPS_ADDR 0x10
// uncomment this only if your LoPy runs on a EXPANSION BOARD
//#define HAS_LED GPIO_NUM_12 // use if LoPy is on Expansion Board, this has a user LED
//#define HAS_LED (12) // use if LoPy is on Expansion Board, this has a user LED
//#define LED_ACTIVE_LOW 1 // use if LoPy is on Expansion Board, this has a user LED
//#define HAS_BUTTON GPIO_NUM_13 // user button on expansion board
//#define HAS_BUTTON (13) // user button on expansion board
//#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
//#define HAS_BATTERY_PROBE ADC1_GPIO39_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
//#define BATT_FACTOR 2 // voltage divider 1MOhm/1MOhm -> expansion board 3.0
//#define BATT_FACTOR 4 // voltage divider 115kOhm/56kOhm -> expansion board 2.0
#endif

View File

@ -1,36 +1,43 @@
#ifndef _LOPY4_H
#define _LOPY4_H
#include <stdint.h>
// Hardware related definitions for Pycom LoPy4 Board
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1276_radio 1
//#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0 (P2)
#define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0 (P2)
#define BOARD_HAS_PSRAM // use extra 4MB extern RAM
// Hardware pin definitions for Pycom LoPy4 board
#define PIN_SPI_SS GPIO_NUM_18
#define PIN_SPI_MOSI GPIO_NUM_27
#define PIN_SPI_MISO GPIO_NUM_19
#define PIN_SPI_SCK GPIO_NUM_5
#define RST LMIC_UNUSED_PIN
#define DIO0 GPIO_NUM_23 // LoRa IRQ
#define DIO1 GPIO_NUM_23 // Pin tied via diode to DIO0
#define DIO2 GPIO_NUM_23 // Pin tied via diode to DIO0
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST LMIC_UNUSED_PIN
#define LORA_IO0 (23) // LoRa IRQ
#define LORA_IO1 (23) // Pin tied via diode to DIO0
#define LORA_IO2 (23) // Pin tied via diode to DIO0
// select WIFI antenna (internal = onboard / external = u.fl socket)
#define HAS_ANTENNA_SWITCH GPIO_NUM_21 // pin for switching wifi antenna (P12)
#define HAS_ANTENNA_SWITCH (21) // pin for switching wifi antenna (P12)
#define WIFI_ANTENNA 0 // 0 = internal, 1 = external
// uncomment this only if your LoPy runs on a PYTRACK BOARD
//#define HAS_GPS 1
//#define GPS_QUECTEL_L76 GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21)
//#define GPS_I2C GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21)
//#define GPS_ADDR 0x10
// uncomment this only if your LoPy runs on a EXPANSION BOARD
#define HAS_LED GPIO_NUM_12 // use if LoPy is on Expansion Board, this has a user LED
#define HAS_LED (12) // use if LoPy is on Expansion Board, this has a user LED
#define LED_ACTIVE_LOW 1 // use if LoPy is on Expansion Board, this has a user LED
#define HAS_BUTTON GPIO_NUM_13 // user button on expansion board
#define HAS_BUTTON (13) // user button on expansion board
#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown
#define HAS_BATTERY_PROBE ADC1_GPIO39_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
#define BATT_FACTOR 2 // voltage divider 1MOhm/1MOhm -> expansion board 3.0
//#define BATT_FACTOR 4 // voltage divider 115kOhm/56kOhm -> expansion board 2.0
#endif

View File

@ -1,3 +1,8 @@
#ifndef _OCTOPUS_H
#define _OCTOPUS_H
#include <stdint.h>
// Hardware related definitions for #IoT Octopus32 with the Adafruit LoRaWAN Wing
// You can use this configuration also with the Adafruit ESP32 Feather + the LoRaWAN Wing
// In this config we use the Adafruit OLED Wing which is only 128x32 pixel, need to find a smaller font
@ -15,27 +20,21 @@
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1276_radio 1 // RFM95 module
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS 14 //14 // ESP32 GPIO5 (Pin5) -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI 18 // ESP32 GPIO23 (Pin23) -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK 5 // ESP32 GPIO18 (Pin18) -- SX1276 SCK (Pin16) SPI Clock Input
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (14)
#define LORA_MISO (19)
#define LORA_MOSI (18)
#define LORA_RST LMIC_UNUSED_PIN
#define LORA_IO0 (33)
#define LORA_IO1 (33)
#define LORA_IO2 LMIC_UNUSED_PIN
//GPIO_NUM_
// non arduino pin definitions
#define RST LMIC_UNUSED_PIN // ESP32 GPIO25 (Pin25) -- SX1276 NRESET (Pin7) Reset Trigger Input
#define DIO0 33 // ESP32 GPIO27 (Pin27) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
#define DIO1 33 // ESP32 GPIO26 (Pin26) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
#define DIO2 LMIC_UNUSED_PIN // 4 ESP32 GPIO4 (Pin4) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
#define DIO5 LMIC_UNUSED_PIN // 35 ESP32 GPIO35 (Pin35) -- SX1276 DIO5 not used by LMIC for LoRa (Timeout for FSK only)
// Hardware pin definitions for LoRaNode32 Board with OLED I2C Display
#define OLED_RST U8X8_PIN_NONE // Not reset pin
// Pins for I2C interface of OLED Display
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // U8X8_SSD1306_128X32_UNIVISION_SW_I2C //
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
#define I2C_SDA 23 //21 // ESP32 GPIO14 (Pin14) -- OLED SDA
#define I2C_SCL 22 //22 // ESP32 GPIO12 (Pin12) -- OLED SCL
#define MY_OLED_SDA (23)
#define MY_OLED_SCL (22)
#define MY_OLED_RST U8X8_PIN_NONE
// I2C config for Microchip 24AA02E64 DEVEUI unique address
//#define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64
//#define MCP_24AA02E64_MAC_ADDRESS 0xF8 // Memory adress of unique deveui 64 bits
#endif

View File

@ -1,3 +1,8 @@
#ifndef _TTGOBEAM_H
#define _TTGOBEAM_H
#include <stdint.h>
// Hardware related definitions for TTGO T-Beam board
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
@ -14,15 +19,15 @@
#define HAS_GPS 1 // use on board GPS
#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M or 7M with default configuration
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST LMIC_UNUSED_PIN
#define LORA_IO0 (26)
#define LORA_IO1 (32) // !! NEEDS EXTERNAL WIRING !!
//#define LORA_IO1 (33) // for T-Beam T22_V05 and T22_V07, other versions may need external wiring
#define LORA_IO2 LMIC_UNUSED_PIN
// non arduino pin definitions
#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 <-> HPD13A IO0
#define DIO1 GPIO_NUM_32 // Lora1 <-> HPD13A IO1 // !! NEEDS EXTERNAL WIRING !!
//#define DIO1 GPIO_NUM_33 // Lora1 <-> HPD13A IO1 // for T-Beam T22_V05 only
#define DIO2 LMIC_UNUSED_PIN // Lora2 <-> HPD13A IO2 // not needed for LoRa
#endif

View File

@ -1,3 +1,8 @@
#ifndef _TTGOV1_H
#define _TTGOV1_H
#include <stdint.h>
// Hardware related definitions for TTGOv1 board
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
@ -6,23 +11,23 @@
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
#define HAS_LED GPIO_NUM_2 // white LED on board
#define HAS_LED (2) // white LED on board
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
#define HAS_BUTTON GPIO_NUM_0 // button "PRG" on board
#define HAS_BUTTON (0) // button "PRG" on board
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
// Pins for I2C interface of OLED Display
#define MY_OLED_SDA (4)
#define MY_OLED_SCL (15)
#define MY_OLED_RST (16)
// non arduino pin definitions
#define RST GPIO_NUM_14 // ESP32 GPIO14 (Pin14) -- SX1276 NRESET (Pin7) Reset Trigger Input
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 (Pin15) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
#define DIO1 GPIO_NUM_33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
#define DIO2 LMIC_UNUSED_PIN // 32 ESP32 GPIO32 (Pin12) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST (14)
#define LORA_IO0 (26)
#define LORA_IO1 (33)
#define LORA_IO2 LMIC_UNUSED_PIN
// Hardware pin definitions for TTGOv1 Board with OLED SSD1306 I2C Display
#define OLED_RST GPIO_NUM_16 // ESP32 GPIO16 (Pin16) -- SD1306 Reset
#define I2C_SDA GPIO_NUM_4 // ESP32 GPIO4 (Pin4) -- SD1306 Data
#define I2C_SCL GPIO_NUM_15 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
#endif

View File

@ -1,3 +1,8 @@
#ifndef _TTGOV2_H
#define _TTGOV2_H
#include <stdint.h>
// Hardware related definitions for TTGO V2 Board
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
@ -11,46 +16,19 @@
// disable brownout detection (needed on TTGOv2 for battery powered operation)
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS GPIO_NUM_18 // ESP32 GPIO18 (Pin18) -- HPD13A NSS/SEL (Pin4) SPI Chip Select Input
#define PIN_SPI_MOSI GPIO_NUM_27 // ESP32 GPIO27 (Pin27) -- HPD13A MOSI/DSI (Pin6) SPI Data Input
#define PIN_SPI_MISO GPIO_NUM_19 // ESP32 GPIO19 (Pin19) -- HPD13A MISO/DSO (Pin7) SPI Data Output
#define PIN_SPI_SCK GPIO_NUM_5 // ESP32 GPIO5 (Pin5) -- HPD13A SCK (Pin5) SPI Clock Input
// Pins for I2C interface of OLED Display
#define MY_OLED_SDA (21)
#define MY_OLED_SCL (22)
#define MY_OLED_RST U8X8_PIN_NONE
// non arduino pin definitions
#define RST LMIC_UNUSED_PIN // connected to ESP32 RST/EN
#define DIO0 GPIO_NUM_26 // ESP32 GPIO26 wired on PCB to HPD13A
#define DIO1 GPIO_NUM_33 // HPDIO1 on pcb, needs to be wired external to GPIO33
#define DIO2 LMIC_UNUSED_PIN // 32 HPDIO2 on pcb, needs to be wired external to GPIO32 (not necessary for LoRa, only FSK)
// Pins for LORA chip SPI interface, reset line and interrupt lines
#define LORA_SCK (5)
#define LORA_CS (18)
#define LORA_MISO (19)
#define LORA_MOSI (27)
#define LORA_RST LMIC_UNUSED_PIN
#define LORA_IO0 (26)
#define LORA_IO1 (33)
#define LORA_IO2 LMIC_UNUSED_PIN
// Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display
#define OLED_RST U8X8_PIN_NONE // connected to CPU RST/EN
#define I2C_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2
#define I2C_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
/* source:
https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-2/11973
TTGO LoRa32 V2:
ESP32 LoRa (SPI) Display (I2C) LED
----------- ---------- ------------- ------------------
GPIO5 SCK SCK
GPIO27 MOSI MOSI
GPIO19 MISO MISO
GPIO18 SS NSS
EN RST RST
GPIO26 DIO0
GPIO33 DIO1 (see #1)
GPIO32 DIO2 (see #2)
GPIO22 SCL SCL
GPIO21 SDA SDA
GPIO22 useless (see #3)
#1 Required (used by LMIC for LoRa).
Not on-board wired to any GPIO. Must be manually wired. <<-- necessary for paxcounter
#2 Optional (used by LMIC for FSK but not for LoRa). <<-- NOT necessary for paxcounter
Not on-board wired to any GPIO. When needed: must be manually wired.
#3 GPIO22 is already used for SCL therefore LED cannot be used without conflicting with I2C and display.
*/
#endif

Some files were not shown because too many files have changed in this diff Show More