/******************************************************************************************
* Copyright 2017 Ideetron B.V.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
******************************************************************************************/
/****************************************************************************************
* File: RFM95.cpp
* Author: Gerben den Hartog
* Compagny: Ideetron B.V.
* Website: http://www.ideetron.nl/LoRa
* E-mail: info@ideetron.nl
****************************************************************************************/
/****************************************************************************************
* Created on: 06-01-2017
* Supported Hardware: ID150119-02 Nexus board with RFM95
****************************************************************************************/
#include
#include
#include "RFM95.h"
#include "Config.h"
/**
* Lora Frequencies
* Tested on all subbands in US915
*/
#if defined(US_915)
#if defined(SUBND_0)//[902.3 - 903.7] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE1, 0x93, 0x59 }, //Channel [0], 902.3 MHz / 61.035 Hz = 14783321 = 0xE19359
{ 0xE1, 0xA0, 0x26 }, //Channel [1], 902.5 MHz / 61.035 Hz = 14786598 = 0xE1A026
{ 0xE1, 0xAC, 0xF3 }, //Channel [2], 902.7 MHz / 61.035 Hz = 14789875 = 0xE1ACF3
{ 0xE1, 0xB9, 0xBF }, //Channel [3], 902.9 MHz / 61.035 Hz = 14793151 = 0xE1B9BF
{ 0xE1, 0xC6, 0x8C }, //Channel [4], 903.1 MHz / 61.035 Hz = 14796428 = 0xE1C68C
{ 0xE1, 0xD3, 0x59 }, //Channel [5], 903.3 MHz / 61.035 Hz = 14799705 = 0xE1D359
{ 0xE1, 0xE0, 0x26 }, //Channel [6], 903.5 MHz / 61.035 Hz = 14802982 = 0xE1E026
{ 0xE1, 0xEC, 0xF3 }, //Channel [7], 903.7 MHz / 61.035 Hz = 14806259 = 0xE1ECF3
};
#elif defined(SUBND_1)//[903.9 - 905.3] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE1, 0xF9, 0xC0 }, //Channel [0], 903.9 MHz / 61.035 Hz = 14809536 = 0xE1F9C0
{ 0xE2, 0x06, 0x8C }, //Channel [1], 904.1 MHz / 61.035 Hz = 14812812 = 0xE2068C
{ 0xE2, 0x13, 0x59 }, //Channel [2], 904.3 MHz / 61.035 Hz = 14816089 = 0xE21359
{ 0xE2, 0x20, 0x26 }, //Channel [3], 904.5 MHz / 61.035 Hz = 14819366 = 0xE22026
{ 0xE2, 0x2C, 0xF3 }, //Channel [4], 904.7 MHz / 61.035 Hz = 14822643 = 0xE22CF3
{ 0xE2, 0x39, 0xC0 }, //Channel [5], 904.9 MHz / 61.035 Hz = 14825920 = 0xE239C0
{ 0xE2, 0x46, 0x8C }, //Channel [6], 905.1 MHz / 61.035 Hz = 14829196 = 0xE2468C
{ 0xE2, 0x53, 0x59 }, //Channel [7], 905.3 MHz / 61.035 Hz = 14832473 = 0xE25359
};
#elif defined(SUBND_2)//[905.5 - 906.9] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE2, 0x60, 0x26 }, //Channel [0], 905.5 MHz / 61.035 Hz = 14835750 = 0xE26026
{ 0xE2, 0x6C, 0xF3 }, //Channel [1], 905.7 MHz / 61.035 Hz = 14839027 = 0xE26CF3
{ 0xE2, 0x79, 0xC0 }, //Channel [2], 905.9 MHz / 61.035 Hz = 14842304 = 0xE279C0
{ 0xE2, 0x86, 0x8C }, //Channel [3], 906.1 MHz / 61.035 Hz = 14845580 = 0xE2868C
{ 0xE2, 0x93, 0x59 }, //Channel [4], 906.3 MHz / 61.035 Hz = 14848857 = 0xE29359
{ 0xE2, 0xA0, 0x26 }, //Channel [5], 906.5 MHz / 61.035 Hz = 14852134 = 0xE2A026
{ 0xE2, 0xAC, 0xF3 }, //Channel [6], 906.7 MHz / 61.035 Hz = 14855411 = 0xE2ACF3
{ 0xE2, 0xB9, 0xC0 }, //Channel [7], 906.9 MHz / 61.035 Hz = 14858688 = 0xE2B9C0
};
#elif defined(SUBND_3)//[907.1 - 908.5] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE2, 0xC6, 0x8C }, //Channel [0], 907.1 MHz / 61.035 Hz = 14861964 = 0xE2C68C
{ 0xE2, 0xD3, 0x59 }, //Channel [1], 907.3 MHz / 61.035 Hz = 14865241 = 0xE2D359
{ 0xE2, 0xE0, 0x26 }, //Channel [2], 907.5 MHz / 61.035 Hz = 14868518 = 0xE2E026
{ 0xE2, 0xEC, 0xF3 }, //Channel [3], 907.7 MHz / 61.035 Hz = 14871795 = 0xE2ECF3
{ 0xE2, 0xF9, 0xC0 }, //Channel [4], 907.9 MHz / 61.035 Hz = 14875072 = 0xE2F9C0
{ 0xE3, 0x06, 0x8C }, //Channel [5], 908.1 MHz / 61.035 Hz = 14878348 = 0xE3068C
{ 0xE3, 0x13, 0x59 }, //Channel [6], 908.3 MHz / 61.035 Hz = 14881625 = 0xE31359
{ 0xE3, 0x20, 0x26 }, //Channel [7], 908.5 MHz / 61.035 Hz = 14884902 = 0xE32026
};
#elif defined(SUBND_4)//[908.7 - 910.1] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE3, 0x2C, 0xF3 }, //Channel [0], 908.7 MHz / 61.035 Hz = 14888179 = 0xE32CF3
{ 0xE3, 0x39, 0xC0 }, //Channel [1], 908.9 MHz / 61.035 Hz = 14891456 = 0xE339C0
{ 0xE3, 0x46, 0x8D }, //Channel [2], 909.1 MHz / 61.035 Hz = 14894733 = 0xE3468D
{ 0xE3, 0x53, 0x59 }, //Channel [3], 909.3 MHz / 61.035 Hz = 14898009 = 0xE35359
{ 0xE3, 0x60, 0x26 }, //Channel [4], 909.5 MHz / 61.035 Hz = 14901286 = 0xE36026
{ 0xE3, 0x6C, 0xF3 }, //Channel [5], 909.7 MHz / 61.035 Hz = 14904563 = 0xE36CF3
{ 0xE3, 0x79, 0xC0 }, //Channel [6], 909.9 MHz / 61.035 Hz = 14907840 = 0xE379C0
{ 0xE3, 0x86, 0x8D }, //Channel [7], 910.1 MHz / 61.035 Hz = 14911117 = 0xE3868D
};
#elif defined(SUBND_5)//[910.3 - 911.7] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE3, 0x93, 0x59 }, //Channel [0], 910.3 MHz / 61.035 Hz = 14914393 = 0xE39359
{ 0xE3, 0xA0, 0x26 }, //Channel [1], 910.5 MHz / 61.035 Hz = 14917670 = 0xE3A026
{ 0xE3, 0xAC, 0xF3 }, //Channel [2], 910.7 MHz / 61.035 Hz = 14920947 = 0xE3ACF3
{ 0xE3, 0xB9, 0xC0 }, //Channel [3], 910.9 MHz / 61.035 Hz = 14924224 = 0xE3B9C0
{ 0xE3, 0xC6, 0x8D }, //Channel [4], 911.1 MHz / 61.035 Hz = 14927501 = 0xE3C68D
{ 0xE3, 0xD3, 0x59 }, //Channel [5], 911.3 MHz / 61.035 Hz = 14930777 = 0xE3D359
{ 0xE3, 0xE0, 0x26 }, //Channel [6], 911.5 MHz / 61.035 Hz = 14934054 = 0xE3E026
{ 0xE3, 0xEC, 0xF3 }, //Channel [7], 911.7 MHz / 61.035 Hz = 14937331 = 0xE3ECF3
};
#elif defined(SUBND_6)//[911.9 - 913.3] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE3, 0xF9, 0xC0 }, //Channel [0], 911.9 MHz / 61.035 Hz = 14940608 = 0xE3F9C0
{ 0xE4, 0x06, 0x8D }, //Channel [1], 912.1 MHz / 61.035 Hz = 14943885 = 0xE4068D
{ 0xE4, 0x13, 0x59 }, //Channel [2], 912.3 MHz / 61.035 Hz = 14947161 = 0xE41359
{ 0xE4, 0x20, 0x26 }, //Channel [3], 912.5 MHz / 61.035 Hz = 14950438 = 0xE42026
{ 0xE4, 0x2C, 0xF3 }, //Channel [4], 912.7 MHz / 61.035 Hz = 14953715 = 0xE42CF3
{ 0xE4, 0x39, 0xC0 }, //Channel [5], 912.9 MHz / 61.035 Hz = 14956992 = 0xE439C0
{ 0xE4, 0x46, 0x8D }, //Channel [6], 913.1 MHz / 61.035 Hz = 14960269 = 0xE4468D
{ 0xE4, 0x53, 0x5A }, //Channel [7], 913.3 MHz / 61.035 Hz = 14963546 = 0xE4535A
};
#elif defined(SUBND_7)//[913.5 - 914.9] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE4, 0x60, 0x26 }, //Channel [0], 913.5 MHz / 61.035 Hz = 14966822 = 0xE46026
{ 0xE4, 0x6C, 0xF3 }, //Channel [1], 913.7 MHz / 61.035 Hz = 14970099 = 0xE46CF3
{ 0xE4, 0x79, 0xC0 }, //Channel [2], 913.9 MHz / 61.035 Hz = 14973376 = 0xE479C0
{ 0xE4, 0x86, 0x8D }, //Channel [3], 914.1 MHz / 61.035 Hz = 14976653 = 0xE4868D
{ 0xE4, 0x93, 0x5A }, //Channel [4], 914.3 MHz / 61.035 Hz = 14979930 = 0xE4935A
{ 0xE4, 0xA0, 0x26 }, //Channel [5], 914.5 MHz / 61.035 Hz = 14983206 = 0xE4A026
{ 0xE4, 0xAC, 0xF3 }, //Channel [6], 914.7 MHz / 61.035 Hz = 14986483 = 0xE4ACF3
{ 0xE4, 0xB9, 0xC0 }, //Channel [7], 914.9 MHz / 61.035 Hz = 14989760 = 0xE4B9C0
};
#endif
static const PROGMEM unsigned char LoRa_RX_Freq[8][3] = {
{ 0xE6, 0xD3, 0x5A}, //Rcv Channel [0] 923.3 Mhz / 61.035 Hz = 15127386 = 0xE6D35A
{ 0xE6, 0xF9, 0xC0}, //Rcv Channel [1] 923.9 Mhz / 61.035 Hz = 15137216 = 0xE6F9C0
{ 0xE7, 0x20, 0x27}, //Rcv Channel [2] 924.5 Mhz / 61.035 Hz = 15147047 = 0xE72027
{ 0xE7, 0x46, 0x8D}, //Rcv Channel [3] 925.1 Mhz / 61.035 Hz = 15156877 = 0xE7468D
{ 0xE7, 0x6C, 0xF4}, //Rcv Channel [4] 925.7 Mhz / 61.035 Hz = 15166708 = 0xE76CF4
{ 0xE7, 0x93, 0x5A}, //Rcv Channel [5] 926.3 Mhz / 61.035 Hz = 15176538 = 0xE7935A
{ 0xE7, 0xB9, 0xC0}, //Rcv Channel [6] 926.9 Mhz / 61.035 Hz = 15186368 = 0xE7B9C0
{ 0xE7, 0xE0, 0x27}, //Rcv Channel [7] 927.5 Mhz / 61.035 Hz = 15196199 = 0xE7E027
};
#elif defined(AU_915)
#if defined(SUBND_0)//[915.2 - 916.6] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE4, 0xCC, 0xF3 }, //Channel [0], 915,2 MHz / 61.035 Hz = 14994675 = 0xE4CCF3
{ 0xE4, 0xD9, 0xC0 }, //Channel [1], 915,4 MHz / 61.035 Hz = 14997952 = 0xE4D9C0
{ 0xE4, 0xE6, 0x8D }, //Channel [2], 915,6 MHz / 61.035 Hz = 15001229 = 0xE4E68D
{ 0xE4, 0xF3, 0x5A }, //Channel [3], 915,8 MHz / 61.035 Hz = 15004506 = 0xE4F35A
{ 0xE5, 0x00, 0x26 }, //Channel [4], 916,0 MHz / 61.035 Hz = 15007782 = 0xE50026
{ 0xE5, 0x0C, 0xF3 }, //Channel [5], 916,2 MHz / 61.035 Hz = 15011059 = 0xE50CF3
{ 0xE5, 0x19, 0xC0 }, //Channel [6], 916,4 MHz / 61.035 Hz = 15014336 = 0xE519C0
{ 0xE5, 0x26, 0x8D }, //Channel [7], 916,6 MHz / 61.035 Hz = 15017613 = 0xE5268D
};
#elif defined(SUBND_1)//[916.8 - 918.2] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE5, 0x33, 0x5A }, //Channel [0], 916,8 MHz / 61.035 Hz = 15020890 = 0xE5335A
{ 0xE5, 0x40, 0x26 }, //Channel [1], 917,0 MHz / 61.035 Hz = 15024166 = 0xE54026
{ 0xE5, 0x4C, 0xF3 }, //Channel [2], 917,2 MHz / 61.035 Hz = 15027443 = 0xE54CF3
{ 0xE5, 0x59, 0xC0 }, //Channel [3], 917,4 MHz / 61.035 Hz = 15030720 = 0xE559C0
{ 0xE5, 0x66, 0x8D }, //Channel [4], 917,6 MHz / 61.035 Hz = 15033997 = 0xE5668D
{ 0xE5, 0x73, 0x5A }, //Channel [5], 917,8 MHz / 61.035 Hz = 15037274 = 0xE5735A
{ 0xE5, 0x80, 0x27 }, //Channel [6], 918,0 MHz / 61.035 Hz = 15040551 = 0xE58027
{ 0xE5, 0x8C, 0xF3 }, //Channel [7], 918,2 MHz / 61.035 Hz = 15043827 = 0xE58CF3
};
#elif defined(SUBND_2)//[918.4 - 919.8] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE5, 0x99, 0xC0 }, //Channel [0], 918,4 MHz / 61.035 Hz = 15047104 = 0xE599C0
{ 0xE5, 0xA6, 0x8D }, //Channel [1], 918,6 MHz / 61.035 Hz = 15050381 = 0xE5A68D
{ 0xE5, 0xB3, 0x5A }, //Channel [2], 918,8 MHz / 61.035 Hz = 15053658 = 0xE5B35A
{ 0xE5, 0xC0, 0x27 }, //Channel [3], 919,0 MHz / 61.035 Hz = 15056935 = 0xE5C027
{ 0xE5, 0xCC, 0xF3 }, //Channel [4], 919,2 MHz / 61.035 Hz = 15060211 = 0xE5CCF3
{ 0xE5, 0xD9, 0xC0 }, //Channel [5], 919,4 MHz / 61.035 Hz = 15063488 = 0xE5D9C0
{ 0xE5, 0xE6, 0x8D }, //Channel [6], 919,6 MHz / 61.035 Hz = 15066765 = 0xE5E68D
{ 0xE5, 0xF3, 0x5A }, //Channel [7], 919,8 MHz / 61.035 Hz = 15070042 = 0xE5F35A
};
#elif defined(SUBND_3)//[920.0 - 921.4] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE6, 0x00, 0x27 }, //Channel [0], 920,0 MHz / 61.035 Hz = 15073319 = 0xE60027
{ 0xE6, 0x0C, 0xF3 }, //Channel [1], 920,2 MHz / 61.035 Hz = 15076595 = 0xE60CF3
{ 0xE6, 0x19, 0xC0 }, //Channel [2], 920,4 MHz / 61.035 Hz = 15079872 = 0xE619C0
{ 0xE6, 0x26, 0x8D }, //Channel [3], 920,6 MHz / 61.035 Hz = 15083149 = 0xE6268D
{ 0xE6, 0x33, 0x5A }, //Channel [4], 920,8 MHz / 61.035 Hz = 15086426 = 0xE6335A
{ 0xE6, 0x40, 0x27 }, //Channel [5], 921,0 MHz / 61.035 Hz = 15089703 = 0xE64027
{ 0xE6, 0x4C, 0xF3 }, //Channel [6], 921,2 MHz / 61.035 Hz = 15092979 = 0xE64CF3
{ 0xE6, 0x59, 0xC0 }, //Channel [7], 921,4 MHz / 61.035 Hz = 15096256 = 0xE659C0
};
#elif defined(SUBND_4)//[921.6 - 923.0] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE6, 0x66, 0x8D }, //Channel [0], 921,6 MHz / 61.035 Hz = 15099533 = 0xE6668D
{ 0xE6, 0x73, 0x5A }, //Channel [1], 921,8 MHz / 61.035 Hz = 15102810 = 0xE6735A
{ 0xE6, 0x80, 0x27 }, //Channel [2], 922,0 MHz / 61.035 Hz = 15106087 = 0xE68027
{ 0xE6, 0x8C, 0xF3 }, //Channel [3], 922,2 MHz / 61.035 Hz = 15109363 = 0xE68CF3
{ 0xE6, 0x99, 0xC0 }, //Channel [4], 922,4 MHz / 61.035 Hz = 15112640 = 0xE699C0
{ 0xE6, 0xA6, 0x8D }, //Channel [5], 922,6 MHz / 61.035 Hz = 15115917 = 0xE6A68D
{ 0xE6, 0xB3, 0x5A }, //Channel [6], 922,8 MHz / 61.035 Hz = 15119194 = 0xE6B35A
{ 0xE6, 0xC0, 0x27 }, //Channel [7], 923,0 MHz / 61.035 Hz = 15122471 = 0xE6C027
};
#elif defined(SUBND_5)//[923.2 - 924.6] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE6, 0xCC, 0xF4 }, //Channel [0], 923,2 MHz / 61.035 Hz = 15125748 = 0xE6CCF4
{ 0xE6, 0xD9, 0xC0 }, //Channel [1], 923,4 MHz / 61.035 Hz = 15129024 = 0xE6D9C0
{ 0xE6, 0xE6, 0x8D }, //Channel [2], 923,6 MHz / 61.035 Hz = 15132301 = 0xE6E68D
{ 0xE6, 0xF3, 0x5A }, //Channel [3], 923,8 MHz / 61.035 Hz = 15135578 = 0xE6F35A
{ 0xE7, 0x00, 0x27 }, //Channel [4], 924,0 MHz / 61.035 Hz = 15138855 = 0xE70027
{ 0xE7, 0x0C, 0xF4 }, //Channel [5], 924,2 MHz / 61.035 Hz = 15142132 = 0xE70CF4
{ 0xE7, 0x19, 0xC0 }, //Channel [6], 924,4 MHz / 61.035 Hz = 15145408 = 0xE719C0
{ 0xE7, 0x26, 0x8D }, //Channel [7], 924,6 MHz / 61.035 Hz = 15148685 = 0xE7268D
};
#elif defined(SUBND_6)//[924.8 - 926.2] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE7, 0x33, 0x5A }, //Channel [0], 924,8 MHz / 61.035 Hz = 15151962 = 0xE7335A
{ 0xE7, 0x40, 0x27 }, //Channel [1], 925,0 MHz / 61.035 Hz = 15155239 = 0xE74027
{ 0xE7, 0x4C, 0xF4 }, //Channel [2], 925,2 MHz / 61.035 Hz = 15158516 = 0xE74CF4
{ 0xE7, 0x59, 0xC0 }, //Channel [3], 925,4 MHz / 61.035 Hz = 15161792 = 0xE759C0
{ 0xE7, 0x66, 0x8D }, //Channel [4], 925,6 MHz / 61.035 Hz = 15165069 = 0xE7668D
{ 0xE7, 0x73, 0x5A }, //Channel [5], 925,8 MHz / 61.035 Hz = 15168346 = 0xE7735A
{ 0xE7, 0x80, 0x27 }, //Channel [6], 926,0 MHz / 61.035 Hz = 15171623 = 0xE78027
{ 0xE7, 0x8C, 0xF4 }, //Channel [7], 926,2 MHz / 61.035 Hz = 15174900 = 0xE78CF4
};
#elif defined(SUBND_7)//[926.4 - 927.8] MHz
static const PROGMEM unsigned char LoRa_TX_Freq[8][3] = {
{ 0xE7, 0x99, 0xC0 }, //Channel [0], 926,4 MHz / 61.035 Hz = 15178176 = 0xE799C0
{ 0xE7, 0xA6, 0x8D }, //Channel [1], 926,6 MHz / 61.035 Hz = 15181453 = 0xE7A68D
{ 0xE7, 0xB3, 0x5A }, //Channel [2], 926,8 MHz / 61.035 Hz = 15184730 = 0xE7B35A
{ 0xE7, 0xC0, 0x27 }, //Channel [3], 927,0 MHz / 61.035 Hz = 15188007 = 0xE7C027
{ 0xE7, 0xCC, 0xF4 }, //Channel [4], 927,2 MHz / 61.035 Hz = 15191284 = 0xE7CCF4
{ 0xE7, 0xD9, 0xC0 }, //Channel [5], 927,4 MHz / 61.035 Hz = 15194560 = 0xE7D9C0
{ 0xE7, 0xE6, 0x8D }, //Channel [6], 927,6 MHz / 61.035 Hz = 15197837 = 0xE7E68D
{ 0xE7, 0xF3, 0x5A }, //Channel [7], 927,8 MHz / 61.035 Hz = 15201114 = 0xE7F35A
};
#endif
static const PROGMEM unsigned char LoRa_RX_Freq[8][3] = {
{ 0xE6, 0xD3, 0x5A}, //Rcv Channel [0] 923.3 Mhz / 61.035 Hz = 15127386 = 0xE6D35A
{ 0xE6, 0xF9, 0xC0}, //Rcv Channel [1] 923.9 Mhz / 61.035 Hz = 15137216 = 0xE6F9C0
{ 0xE7, 0x20, 0x27}, //Rcv Channel [2] 924.5 Mhz / 61.035 Hz = 15147047 = 0xE72027
{ 0xE7, 0x46, 0x8D}, //Rcv Channel [3] 925.1 Mhz / 61.035 Hz = 15156877 = 0xE7468D
{ 0xE7, 0x6C, 0xF4}, //Rcv Channel [4] 925.7 Mhz / 61.035 Hz = 15166708 = 0xE76CF4
{ 0xE7, 0x93, 0x5A}, //Rcv Channel [5] 926.3 Mhz / 61.035 Hz = 15176538 = 0xE7935A
{ 0xE7, 0xB9, 0xC0}, //Rcv Channel [6] 926.9 Mhz / 61.035 Hz = 15186368 = 0xE7B9C0
{ 0xE7, 0xE0, 0x27}, //Rcv Channel [7] 927.5 Mhz / 61.035 Hz = 15196199 = 0xE7E027
};
#elif defined(AS_923)
static const PROGMEM unsigned char [9][3] = {//[923.2 - 924.8] MHz
{ 0xE6, 0xCC, 0xF4 }, //Channel [0], 923.2 MHz / 61.035 Hz = 15125748 = 0xE6CCF4
{ 0xE6, 0xD9, 0xC0 }, //Channel [1], 923.4 MHz / 61.035 Hz = 15129024 = 0xE6D9C0
{ 0xE6, 0xE6, 0x8D }, //Channel [2], 923.6 MHz / 61.035 Hz = 15132301 = 0xE6E68D
{ 0xE6, 0xF3, 0x5A }, //Channel [3], 923.8 MHz / 61.035 Hz = 15135578 = 0xE6F35A
{ 0xE7, 0x00, 0x27 }, //Channel [4], 924.0 MHz / 61.035 Hz = 15138855 = 0xE70027
{ 0xE7, 0x0C, 0xF4 }, //Channel [5], 924.2 MHz / 61.035 Hz = 15142132 = 0xE70CF4
{ 0xE7, 0x19, 0xC0 }, //Channel [6], 924.4 MHz / 61.035 Hz = 15145408 = 0xE719C0
{ 0xE7, 0x26, 0x8D }, //Channel [7], 924.6 MHz / 61.035 Hz = 15148685 = 0xE7268D
{ 0xE7, 0x33, 0x5A }, //Channel [8], 924.8 MHz / 61.035 Hz = 15151962 = 0xE7335A
};
#elif defined(EU_868)
static const PROGMEM unsigned char LoRa_Frequency[9][3] = {//[868.1 - 867.9] MHz
{ 0xD9, 0x06, 0x8B }, //Channel [0], 868.1 MHz / 61.035 Hz = 14222987 = 0xD9068B
{ 0xD9, 0x13, 0x58 }, //Channel [1], 868.3 MHz / 61.035 Hz = 14226264 = 0xD91358
{ 0xD9, 0x20, 0x24 }, //Channel [2], 868.5 MHz / 61.035 Hz = 14229540 = 0xD92024
{ 0xD8, 0xC6, 0x8B }, //Channel [3], 867.1 MHz / 61.035 Hz = 14206603 = 0xD8C68B
{ 0xD8, 0xD3, 0x58 }, //Channel [4], 867.3 MHz / 61.035 Hz = 14209880 = 0xD8D358
{ 0xD8, 0xE0, 0x24 }, //Channel [5], 867.5 MHz / 61.035 Hz = 14213156 = 0xD8E024
{ 0xD8, 0xEC, 0xF1 }, //Channel [6], 867.7 MHz / 61.035 Hz = 14216433 = 0xD8ECF1
{ 0xD8, 0xF9, 0xBE }, //Channel [7], 867.9 MHz / 61.035 Hz = 14219710 = 0xD8F9BE
{ 0xD9, 0x61, 0xBE }, // RX2 Receive channel 869.525 MHz / 61.035 Hz = 14246334 = 0xD961BE
};
#elif defined(IN_865)
static const PROGMEM unsigned char LoRa_Frequency[9][3] = {//[865 - 867] MHz
{ 0xD8, 0x44, 0x24 }, //Channel [0], 865.0625 MHz / 61.035 Hz = 14173220 = 0xD84424
{ 0xD8, 0x59, 0xE7 }, //Channel [1], 865.4025 MHz / 61.035 Hz = 14178791 = 0xD859E7
{ 0xD8, 0x66, 0xB4 }, //Channel [2], 865.6025 MHz / 61.035 Hz = 14182068 = 0xD866B4
{ 0xD8, 0x7F, 0x2F }, //Channel [3], 865.9850 MHz / 61.035 Hz = 14188335 = 0xD87F2F
{ 0xD8, 0x8B, 0xFB }, //Channel [4], 866.1850 MHz / 61.035 Hz = 14191611 = 0xD88BFB
{ 0xD8, 0x98, 0xC8 }, //Channel [5], 866.3850 MHz / 61.035 Hz = 14194888 = 0xD898C8
{ 0xD8, 0xA5, 0x95 }, //Channel [6], 866.5850 MHz / 61.035 Hz = 14198165 = 0xD8A595
{ 0xD8, 0xB2, 0x62 }, //Channel [7], 866.7850 MHz / 61.035 Hz = 14201442 = 0xD8B262
{ 0xD8, 0xA3, 0x57 }, // RX2 Receive channel 866.550 MHz / 61.035 Hz = 14197591 = 0xD8A357
#endif
/*
*****************************************************************************************
* Description : Function that reads a register from the RFM and returns the value
*
* Arguments : RFM_Address Address of register to be read
*
* Returns : Value of the register
*****************************************************************************************
*/
static unsigned char RFM_Read(unsigned char RFM_Address)
{
unsigned char RFM_Data;
//Add transactions in Read and Write methods
SPI.beginTransaction(SPISettings(4000000,MSBFIRST,SPI_MODE1));
//Set NSS pin low to start SPI communication
digitalWrite(RFM_pins.CS,LOW);
//Send Address
SPI.transfer(RFM_Address);
//Send 0x00 to be able to receive the answer from the RFM
RFM_Data = SPI.transfer(0x00);
//Set NSS high to end communication
digitalWrite(RFM_pins.CS,HIGH);
//End the transaction so that other hardware can use the bus
SPI.endTransaction();
#ifdef DEBUG
Serial.print("SPI Read ADDR: ");
Serial.print(RFM_Address, HEX);
Serial.print(" DATA: ");
Serial.println(RFM_Data, HEX);
#endif
//Return received data
return RFM_Data;
}
/********************************************************************************************
* Description : Change Spread Factor and Band Width
*
* Arguments: _SF = {6,7,8,9,10,11,12}
* _BW = {0x00 -> 7.8khz , 0x01 -> 10.4khz, 0x02 -> 15.6khz, 0x03 -> 20.8khz,
* 0x04 -> 31.25khz , 0x05 -> 41.7khz, 0x06 -> 62.5khz, 0x07 -> 125khz,
* 0x08 -> 250khz , 0x09 -> 500khz}
********************************************************************************************/
static void RFM_change_SF_BW(unsigned char _SF, unsigned char _BW)
{
RFM_Write(RFM_REG_MODEM_CONFIG2, (_SF << 4) | 0b0100); //SFx CRC On
RFM_Write(RFM_REG_MODEM_CONFIG1,(_BW << 4) | 0x02); //x kHz 4/5 coding rate explicit header mode
if(_SF==12 || _SF==11)
RFM_Write(RFM_REG_MODEM_CONFIG3, 0x0C); //Low datarate optimization on AGC auto on
else
RFM_Write(RFM_REG_MODEM_CONFIG3, 0x04); //Mobile node, low datarate optimization on AGC acorging to register LnaGain
}
/*
*****************************************************************************************
* Description : Function to change the datarate of the RFM module. Setting the following
* register: Spreading factor, Bandwidth and low datarate optimisation.
*
* Arguments : Datarate the datarate to set
*****************************************************************************************
*/
static void RFM_Change_Datarate(unsigned char Datarate)
{
#if defined(US_915)
switch (Datarate) {
case 0x00: // SF10BW125
RFM_change_SF_BW(10,0x07);
break;
case 0x01: // SF9BW125
RFM_change_SF_BW(9,0x07);
break;
case 0x02: // SF8BW125
RFM_change_SF_BW(8,0x07);
break;
case 0x03: // SF7BW125
RFM_change_SF_BW(7,0x07);
break;
case 0x04: // SF8BW500
RFM_change_SF_BW(8,0x09);
break;
case 0x08: // SF12BW500
RFM_change_SF_BW(12,0x09);
break;
case 0x09: // SF11BW500
RFM_change_SF_BW(11,0x09);
break;
case 0x0A: // SF10BW500
RFM_change_SF_BW(10,0x09);
break;
case 0x0B: // SF9BW500
RFM_change_SF_BW(9,0x09);
break;
case 0x0C: // SF8BW500
RFM_change_SF_BW(8,0x09);
break;
case 0x0D: // SF7BW500
RFM_change_SF_BW(7,0x09);
break;
}
#elif defined(AU_915)
switch (Datarate) {
case 0x00: // SF10BW125
RFM_change_SF_BW(10,0x07);
break;
case 0x01: // SF9BW125
RFM_change_SF_BW(9,0x07);
break;
case 0x02: // SF8BW125
RFM_change_SF_BW(8,0x07);
break;
case 0x03: // SF7BW125
RFM_change_SF_BW(7,0x07);
break;
case 0x04: // SF8BW500
RFM_change_SF_BW(8,0x09);
break;
case 0x08: // SF12BW500
RFM_change_SF_BW(12,0x09);
break;
case 0x09: // SF11BW500
RFM_change_SF_BW(11,0x09);
break;
case 0x0A: // SF10BW500
RFM_change_SF_BW(10,0x09);
break;
case 0x0B: // SF9BW500
RFM_change_SF_BW(9,0x09);
break;
case 0x0C: // SF8BW500
RFM_change_SF_BW(8,0x09);
break;
case 0x0D: // SF7BW500
RFM_change_SF_BW(7,0x09);
break;
}
#else //EU_868 or AS_923
switch (Datarate) {
case 0x00: // SF12BW125
RFM_change_SF_BW(12,0x07);
break;
case 0x01: // SF11BW125
RFM_change_SF_BW(11,0x07);
break;
case 0x02: // SF10BW125
RFM_change_SF_BW(10,0x07);
break;
case 0x03: // SF9BW125
RFM_change_SF_BW(9,0x07);
break;
case 0x04: // SF8BW125
RFM_change_SF_BW(8,0x07);
break;
case 0x05: // SF7BW125
RFM_change_SF_BW(7,0x07);
break;
case 0x06: // SF7BW250
RFM_change_SF_BW(7,0x08);
break;
}
#endif
}
/*
*****************************************************************************************
* Description : Function to change the channel of the RFM module. Setting the following
* register: Channel
*
* Arguments : Channel the channel to set
*****************************************************************************************
*/
static void RFM_Change_Channel(unsigned char Channel)
{
#if defined(AS_923)
if (Channel <= 0x08)
for(unsigned char i = 0 ; i < 3 ; ++i)
RFM_Write(RFM_REG_FR_MSB + i, pgm_read_byte(&(LoRa_Frequency[Channel][i])));
else if (Channel == 0x10)
for(unsigned char i = 0 ; i < 3 ; ++i)
RFM_Write(RFM_REG_FR_MSB + i, pgm_read_byte(&(LoRa_Frequency[0][i])));
#elif defined(EU_868)
// in EU_868 v1.02 uses same freq for uplink and downlink
if (Channel <= 0x08)
for(unsigned char i = 0 ; i < 3 ; ++i)
RFM_Write(RFM_REG_FR_MSB + i, pgm_read_byte(&(LoRa_Frequency[Channel][i])));
#else //US915 or AU_915
if (Channel <= 0x07)
for(unsigned char i = 0 ; i < 3 ; ++i)
RFM_Write(RFM_REG_FR_MSB + i, pgm_read_byte(&(LoRa_TX_Freq[Channel][i])));
else if (Channel >= 0x08 && Channel <= 0x0F)
for(unsigned char i = 0 ; i < 3 ; ++i) {
RFM_Write(RFM_REG_FR_MSB + i, pgm_read_byte(&(LoRa_RX_Freq[Channel - 0x08][i])));
}
#endif
}
/*
*****************************************************************************************
* Description: Function used to initialize the RFM module on startup
*****************************************************************************************
*/
bool RFM_Init()
{
uint8_t ver = RFM_Read(0x42);
if(ver!=18){
return 0;
}
//Switch RFM to sleep
//DON'T USE Switch mode function
RFM_Write(RFM_REG_OP_MODE, RFM_MODE_SLEEP);
//Wait until RFM is in sleep mode
delay(50);
//Set RFM in LoRa mode
//DON'T USE Switch mode function
RFM_Write(RFM_REG_OP_MODE ,RFM_MODE_LORA);
//Switch RFM to standby
RFM_Switch_Mode(RFM_MODE_STANDBY);
//Set channel to channel 0
RFM_Change_Channel(CH0);
//Set default power to maximun on US915 TODO AS/AU/EU config
//Set the default output pin as PA_BOOST
RFM_Set_Tx_Power(20, PA_BOOST_PIN);
//Switch LNA boost on
RFM_Write(RFM_REG_LNA,0x23);
//Set RFM To datarate 0 SF12 BW 125 kHz
RFM_Change_Datarate(0x00);
//Rx Timeout set to 37 symbols
RFM_Write(RFM_REG_SYM_TIMEOUT_LSB, 0x25);
//RFM_Write(RFM_REG_SYM_TIMEOUT_LSB, 0x05);
//Preamble length set to 8 symbols
//0x0008 + 4 = 12
RFM_Write(RFM_REG_PREAMBLE_MSB,0x00);
RFM_Write(RFM_REG_PREAMBLE_LSB,0x08);
//Set LoRa sync word
RFM_Write(RFM_REG_SYNC_WORD, 0x34);
//Set FIFO pointers
//TX base address
RFM_Write(0x0E,0x80);
//Rx base address
RFM_Write(0x0F,0x00);
return 1;
}
void RFM_Set_Tx_Power(int level, int outputPin)
{
if (RFO_PIN == outputPin) {
// RFO
if (level < 0) {
level = 0;
} else if (level > 14) {
level = 14;
}
RFM_Write(RFM_REG_PA_CONFIG, 0x70 | level);
} else {
// PA BOOST
if (level > 17) {
if (level > 20) {
level = 20;
}
// subtract 3 from level, so 18 - 20 maps to 15 - 17
level -= 3;
// High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.)
RFM_Write(RFM_REG_PA_DAC, 0x87);
RFM_Set_OCP(140);
} else {
if (level < 2) {
level = 2;
}
//Default value PA_HF/LF or +17dBm
RFM_Write(RFM_REG_PA_DAC, 0x84);
RFM_Set_OCP(100);
}
RFM_Write(RFM_REG_PA_CONFIG, 0x80 | (level - 2)); //PA Boost mask
}
}
void RFM_Set_OCP(uint8_t mA)
{
uint8_t ocpTrim = 27;
if (mA <= 120) {
ocpTrim = (mA - 45) / 5;
} else if (mA <=240) {
ocpTrim = (mA + 30) / 10;
}
RFM_Write(RFM_REG_OCP, 0x20 | (0x1F & ocpTrim));
}
/*
*****************************************************************************************
* Description : Function for sending a package with the RFM
*
* Arguments : *RFM_Tx_Package pointer to buffer with data and counter of data
* *LoRa_Settings pointer to sSettings struct
*****************************************************************************************
*/
void RFM_Send_Package(sBuffer *RFM_Tx_Package, sSettings *LoRa_Settings)
{
unsigned char i;
unsigned char RFM_Tx_Location = 0x00;
//Set RFM in Standby mode
RFM_Switch_Mode(RFM_MODE_STANDBY);
//Switch Datarate
RFM_Change_Datarate(LoRa_Settings->Datarate_Tx);
//Switch Channel
RFM_Change_Channel(LoRa_Settings->Channel_Tx);
//Switch DIO0 to TxDone
RFM_Write(RFM_REG_DIO_MAPPING1, 0x40);
//Set IQ to normal values
RFM_Write(RFM_REG_INVERT_IQ,0x27);
RFM_Write(RFM_REG_INVERT_IQ2,0x1D);
//Set payload length to the right length
RFM_Write(RFM_REG_PAYLOAD_LENGTH,RFM_Tx_Package->Counter);
//Get location of Tx part of FiFo
RFM_Tx_Location = RFM_Read(0x0E);
//Set SPI pointer to start of Tx part in FiFo
RFM_Write(RFM_REG_FIFO_ADDR_PTR, RFM_Tx_Location);
//Write Payload to FiFo
for (i = 0;i < RFM_Tx_Package->Counter; i++)
{
RFM_Write(RFM_REG_FIFO, RFM_Tx_Package->Data[i]);
}
//Switch RFM to Tx
RFM_Write(RFM_REG_OP_MODE,0x83);
//Wait for TxDone
while(digitalRead(RFM_pins.DIO0) == LOW);
//Clear interrupt
RFM_Write(RFM_REG_IRQ_FLAGS,0x08);
//Switch RFM back to receive if it is a type C mote
if(LoRa_Settings->Mote_Class == CLASS_C)
{
//Switch Back to Continuous receive
RFM_Continuous_Receive(LoRa_Settings);
}
}
/*
*****************************************************************************************
* Description : Function to switch RFM to single receive mode, used for Class A motes
*
* Arguments : *LoRa_Settings pointer to sSettings struct
*
* Return : message_t Status of the received message
*****************************************************************************************
*/
message_t RFM_Single_Receive(sSettings *LoRa_Settings)
{
message_t Message_Status = NO_MESSAGE;
//Change DIO 0 back to RxDone
RFM_Write(RFM_REG_DIO_MAPPING1, 0x00);
//Invert IQ Back
RFM_Write(RFM_REG_INVERT_IQ, 0x67);
RFM_Write(RFM_REG_INVERT_IQ2, 0x19);
//Change Datarate
RFM_Change_Datarate(LoRa_Settings->Datarate_Rx);
//Change Channel
RFM_Change_Channel(LoRa_Settings->Channel_Rx);
//Switch RFM to Single reception
RFM_Switch_Mode(RFM_MODE_RXSINGLE);
//Wait until RxDone or Timeout
//Wait until timeout or RxDone interrupt
while((digitalRead(RFM_pins.DIO0) == LOW) && (digitalRead(RFM_pins.DIO1) == LOW));
//Check for Timeout
if(digitalRead(RFM_pins.DIO1) == HIGH)
{
//Clear interrupt register
RFM_Write(RFM_REG_IRQ_FLAGS,0xE0);
Message_Status = TIMEOUT;
}
//Check for RxDone
if(digitalRead(RFM_pins.DIO0) == HIGH)
{
Message_Status = NEW_MESSAGE;
}
return Message_Status;
}
/*
*****************************************************************************************
* Description : Function to switch RFM to continuous receive mode, used for Class C motes
*
* Arguments : *LoRa_Settings pointer to sSettings struct
*****************************************************************************************
*/
void RFM_Continuous_Receive(sSettings *LoRa_Settings)
{
//Change DIO 0 back to RxDone and DIO 1 to rx timeout
RFM_Write(RFM_REG_DIO_MAPPING1,0x00);
//Invert IQ Back
RFM_Write(RFM_REG_INVERT_IQ, 0x67);
RFM_Write(RFM_REG_INVERT_IQ2, 0x19);
//Change Datarate and channel.
// This depends on regional parameters
#ifdef EU_868
RFM_Change_Datarate(SF12BW125);
RFM_Change_Channel(CHRX2);
#else
RFM_Change_Datarate(LoRa_Settings->Datarate_Rx);
RFM_Change_Channel(LoRa_Settings->Channel_Rx);
#endif
//Switch to continuous receive
RFM_Switch_Mode(RFM_MODE_RXCONT);
}
/*
*****************************************************************************************
* Description : Function to retrieve a message received by the RFM
*
* Arguments : *RFM_Rx_Package pointer to sBuffer struct containing the data received
* and number of bytes received
*
* Return : message_t Status of the received message
*****************************************************************************************
*/
message_t RFM_Get_Package(sBuffer *RFM_Rx_Package)
{
unsigned char i;
unsigned char RFM_Interrupts = 0x00;
unsigned char RFM_Package_Location = 0x00;
message_t Message_Status;
//Get interrupt register
RFM_Interrupts = RFM_Read(RFM_REG_IRQ_FLAGS);
//Check CRC
if((RFM_Interrupts & 0x20) != 0x20)
{
Message_Status = CRC_OK;
}
else
{
Message_Status = WRONG_MESSAGE;
}
RFM_Package_Location = RFM_Read(0x10); /*Read start position of received package*/
RFM_Rx_Package->Counter = RFM_Read(0x13); /*Read length of received package*/
RFM_Write(RFM_REG_FIFO_ADDR_PTR,RFM_Package_Location); /*Set SPI pointer to start of package*/
for (i = 0x00; i < RFM_Rx_Package->Counter; i++)
{
RFM_Rx_Package->Data[i] = RFM_Read(RFM_REG_FIFO);
}
//Clear interrupt register
RFM_Write(RFM_REG_IRQ_FLAGS,0xE0);
return Message_Status;
}
/*
*****************************************************************************************
* Description : Function that writes a register from the RFM
*
* Arguments : RFM_Address Address of register to be written
* RFM_Data Data to be written
*****************************************************************************************
*/
void RFM_Write(unsigned char RFM_Address, unsigned char RFM_Data)
{
// br: SPI Transfer Debug
#ifdef DEBUG
Serial.print("SPI Write ADDR: ");
Serial.print(RFM_Address, HEX);
Serial.print(" DATA: ");
Serial.println(RFM_Data, HEX);
#endif
//Add transactions in Read and Write methods
SPI.beginTransaction(SPISettings(4000000,MSBFIRST,SPI_MODE0));
//Set NSS pin Low to start communication
digitalWrite(RFM_pins.CS,LOW);
//Send Address with MSB 1 to make it a writ command
SPI.transfer(RFM_Address | 0x80);
//Send Data
SPI.transfer(RFM_Data);
//Set NSS pin High to end communication
digitalWrite(RFM_pins.CS,HIGH);
//End the transaction so that other hardware can use the bus
SPI.endTransaction();
}
/*
*****************************************************************************************
* Description : Function to change the operation mode of the RFM. Switching mode and wait
* for mode ready flag
* DO NOT USE FOR SLEEP
*
* Arguments : Mode the mode to set
*****************************************************************************************
*/
void RFM_Switch_Mode(unsigned char Mode)
{
Mode = Mode | 0x80; //Set high bit for LoRa mode
//Switch mode on RFM module
RFM_Write(RFM_REG_OP_MODE,Mode);
}