IBM LoRa MAC in C (LMiC) mbed library port

Dependents:   lora-temperature LoRaWAN-lmic-app_HS LoRaWAN-lmic-app_huynh

LoRa WAN in C for sx1276 shield

Currently version 1.5


LoRaWAN network configuration for end-device

The following three pieces of information uniquely identifies end-device to network to allow over-the-air activation. These are stored in the end-device prior to join procedure.

AppEUI

Uniquely identifies application provider of end-device.

Least-significant byte first, 8 bytes, use reverse memcpy() to keep same order as shown on lora server.

example C code

static const u1_t APPEUI[8]  = { 0x01, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x25, 0x00 };

This is copied into LMIC by os_getArtEui() callback function in application.

DevEUI

End-device ID, unique to each end-node.

Least-significant byte first, 8 bytes, use reverse memcpy() to keep same order as shown on lora server.

example C code

static const u1_t DEVEUI[8]  = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x0C, 0x25, 0x00 }; 

This is copied into LMIC by os_getDevEui() callback function in application.

AppKey (aka DevKey)

128-bit (16byte) AES key.

example C code

static const u1_t DEVKEY[16] = { 0xe4, 0x72, 0x71, 0xc5, 0xf5, 0x30, 0xa9, 0x9f, 0xcf, 0xc4, 0x0e, 0xab, 0xea, 0xd7, 0x19, 0x42 };

This is copied into LMIC by os_getDevKey() callback function in application.

Using over-the air activation, the end-device (LMIC) performs a join procedure every time it starts for first time, or has lost session context information. When join procedure has successfully completed, the end-device will have a network session key (NwkSKey) and an application session key (AppSKey), which are used for encryption and message integrity check.


US915 configuration with http://us01-iot.semtech.com/

  • log in to server
  • click on Applications
  • find your application and click it
  • go to configure motes
  • to create a mote, you may enter a new DevEUI
    • you may copy-paste the 16byte application key from an already existing mote, if you desire.
CHNL_HYBRID125KHz500KHz
defined valuechannelschannel
00 to 764
18 to 1565
216 to 2366
324 to 3167
432 to 3968
540 to 4769
648 to 5570
756 to 6371
undef0 to 6364 to 71
Committer:
mluis
Date:
Thu Jan 22 12:50:49 2015 +0000
Revision:
0:62d1edcc13d1
Child:
1:d3b7bde3995c
Porting of IBM LoRa MAC in C (LMiC) to the mbed platform.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mluis 0:62d1edcc13d1 1 /*******************************************************************************
mluis 0:62d1edcc13d1 2 * Copyright (c) 2014 IBM Corporation.
mluis 0:62d1edcc13d1 3 * All rights reserved. This program and the accompanying materials
mluis 0:62d1edcc13d1 4 * are made available under the terms of the Eclipse Public License v1.0
mluis 0:62d1edcc13d1 5 * which accompanies this distribution, and is available at
mluis 0:62d1edcc13d1 6 * http://www.eclipse.org/legal/epl-v10.html
mluis 0:62d1edcc13d1 7 *
mluis 0:62d1edcc13d1 8 * Contributors:
mluis 0:62d1edcc13d1 9 * IBM Zurich Research Lab - initial API, implementation and documentation
mluis 0:62d1edcc13d1 10 * Semtech Apps Team - Modified to support the MBED sx1276 driver
mluis 0:62d1edcc13d1 11 * library.
mluis 0:62d1edcc13d1 12 * Possibility to use original or Semtech's MBED
mluis 0:62d1edcc13d1 13 * radio driver. The selection is done by setting
mluis 0:62d1edcc13d1 14 * USE_SMTC_RADIO_DRIVER preprocessing directive
mluis 0:62d1edcc13d1 15 * in lmic.h
mluis 0:62d1edcc13d1 16 *******************************************************************************/
mluis 0:62d1edcc13d1 17 #include "lmic.h"
mluis 0:62d1edcc13d1 18
mluis 0:62d1edcc13d1 19 #if USE_SMTC_RADIO_DRIVER
mluis 0:62d1edcc13d1 20 #include "sx1276-hal.h"
mluis 0:62d1edcc13d1 21
mluis 0:62d1edcc13d1 22 /*!
mluis 0:62d1edcc13d1 23 * Syncword for lora networks (nibbles swapped)
mluis 0:62d1edcc13d1 24 */
mluis 0:62d1edcc13d1 25 #define LORA_MAC_SYNCWORD 0x34
mluis 0:62d1edcc13d1 26
mluis 0:62d1edcc13d1 27 /*
mluis 0:62d1edcc13d1 28 * Callback functions prototypes
mluis 0:62d1edcc13d1 29 */
mluis 0:62d1edcc13d1 30 /*!
mluis 0:62d1edcc13d1 31 * @brief Function to be executed on Radio Tx Done event
mluis 0:62d1edcc13d1 32 */
mluis 0:62d1edcc13d1 33 void OnTxDone( void );
mluis 0:62d1edcc13d1 34
mluis 0:62d1edcc13d1 35 /*!
mluis 0:62d1edcc13d1 36 * @brief Function to be executed on Radio Rx Done event
mluis 0:62d1edcc13d1 37 */
mluis 0:62d1edcc13d1 38 void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
mluis 0:62d1edcc13d1 39
mluis 0:62d1edcc13d1 40 /*!
mluis 0:62d1edcc13d1 41 * @brief Function executed on Radio Tx Timeout event
mluis 0:62d1edcc13d1 42 */
mluis 0:62d1edcc13d1 43 void OnTxTimeout( void );
mluis 0:62d1edcc13d1 44
mluis 0:62d1edcc13d1 45 /*!
mluis 0:62d1edcc13d1 46 * @brief Function executed on Radio Rx Timeout event
mluis 0:62d1edcc13d1 47 */
mluis 0:62d1edcc13d1 48 void OnRxTimeout( void );
mluis 0:62d1edcc13d1 49
mluis 0:62d1edcc13d1 50 /*!
mluis 0:62d1edcc13d1 51 * @brief Function executed on Radio Rx Error event
mluis 0:62d1edcc13d1 52 */
mluis 0:62d1edcc13d1 53 void OnRxError( void );
mluis 0:62d1edcc13d1 54
mluis 0:62d1edcc13d1 55 /*!
mluis 0:62d1edcc13d1 56 * @brief Function executed on Radio Fhss Change Channel event
mluis 0:62d1edcc13d1 57 */
mluis 0:62d1edcc13d1 58 void OnFhssChangeChannel( uint8_t channelIndex );
mluis 0:62d1edcc13d1 59
mluis 0:62d1edcc13d1 60 /*!
mluis 0:62d1edcc13d1 61 * @brief Function executed on CAD Done event
mluis 0:62d1edcc13d1 62 */
mluis 0:62d1edcc13d1 63 void OnCadDone( void );
mluis 0:62d1edcc13d1 64
mluis 0:62d1edcc13d1 65 /*
mluis 0:62d1edcc13d1 66 * Radio object declraration
mluis 0:62d1edcc13d1 67 */
mluis 0:62d1edcc13d1 68 SX1276MB1xAS Radio( OnTxDone, OnTxTimeout, OnRxDone, OnRxTimeout, OnRxError, NULL, NULL );
mluis 0:62d1edcc13d1 69
mluis 0:62d1edcc13d1 70 static const u2_t LORA_RXDONE_FIXUP[] = {
mluis 0:62d1edcc13d1 71 [FSK] = us2osticks(0), // ( 0 ticks)
mluis 0:62d1edcc13d1 72 [SF7] = us2osticks(0), // ( 0 ticks)
mluis 0:62d1edcc13d1 73 [SF8] = us2osticks(1648), // ( 54 ticks)
mluis 0:62d1edcc13d1 74 [SF9] = us2osticks(3265), // ( 107 ticks)
mluis 0:62d1edcc13d1 75 [SF10] = us2osticks(7049), // ( 231 ticks)
mluis 0:62d1edcc13d1 76 [SF11] = us2osticks(13641), // ( 447 ticks)
mluis 0:62d1edcc13d1 77 [SF12] = us2osticks(31189), // (1022 ticks)
mluis 0:62d1edcc13d1 78 };
mluis 0:62d1edcc13d1 79
mluis 0:62d1edcc13d1 80 void OnTxDone( void )
mluis 0:62d1edcc13d1 81 {
mluis 0:62d1edcc13d1 82 ostime_t now = os_getTime( );
mluis 0:62d1edcc13d1 83 // save exact tx time
mluis 0:62d1edcc13d1 84 LMIC.txend = now - us2osticks( 43 ); // TXDONE FIXUP
mluis 0:62d1edcc13d1 85
mluis 0:62d1edcc13d1 86 // go from stanby to sleep
mluis 0:62d1edcc13d1 87 Radio.Sleep( );
mluis 0:62d1edcc13d1 88 // run os job (use preset func ptr)
mluis 0:62d1edcc13d1 89 os_setCallback( &LMIC.osjob, LMIC.osjob.func );
mluis 0:62d1edcc13d1 90 }
mluis 0:62d1edcc13d1 91
mluis 0:62d1edcc13d1 92 void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
mluis 0:62d1edcc13d1 93 {
mluis 0:62d1edcc13d1 94 ostime_t now = os_getTime( );
mluis 0:62d1edcc13d1 95 // save exact rx time
mluis 0:62d1edcc13d1 96 LMIC.rxtime = now - LORA_RXDONE_FIXUP[getSf( LMIC.rps )];
mluis 0:62d1edcc13d1 97 // read the PDU and inform the MAC that we received something
mluis 0:62d1edcc13d1 98 LMIC.dataLen = size;
mluis 0:62d1edcc13d1 99 // now read the FIFO
mluis 0:62d1edcc13d1 100 memcpy( LMIC.frame, payload, size );
mluis 0:62d1edcc13d1 101 // read rx quality parameters
mluis 0:62d1edcc13d1 102 LMIC.rxq.snr = snr; // SNR [dB] * 4
mluis 0:62d1edcc13d1 103 LMIC.rxq.rssi = rssi; // RSSI [dBm] (-196...+63)
mluis 0:62d1edcc13d1 104
mluis 0:62d1edcc13d1 105 // go from stanby to sleep
mluis 0:62d1edcc13d1 106 Radio.Sleep( );
mluis 0:62d1edcc13d1 107 // run os job (use preset func ptr)
mluis 0:62d1edcc13d1 108 os_setCallback( &LMIC.osjob, LMIC.osjob.func );
mluis 0:62d1edcc13d1 109 }
mluis 0:62d1edcc13d1 110
mluis 0:62d1edcc13d1 111 void OnTxTimeout( void )
mluis 0:62d1edcc13d1 112 {
mluis 0:62d1edcc13d1 113 ostime_t now = os_getTime( );
mluis 0:62d1edcc13d1 114
mluis 0:62d1edcc13d1 115 // indicate error
mluis 0:62d1edcc13d1 116
mluis 0:62d1edcc13d1 117 // go from stanby to sleep
mluis 0:62d1edcc13d1 118 Radio.Sleep( );
mluis 0:62d1edcc13d1 119 // run os job (use preset func ptr)
mluis 0:62d1edcc13d1 120 os_setCallback( &LMIC.osjob, LMIC.osjob.func );
mluis 0:62d1edcc13d1 121 }
mluis 0:62d1edcc13d1 122
mluis 0:62d1edcc13d1 123 void OnRxTimeout( void )
mluis 0:62d1edcc13d1 124 {
mluis 0:62d1edcc13d1 125 ostime_t now = os_getTime( );
mluis 0:62d1edcc13d1 126 // indicate timeout
mluis 0:62d1edcc13d1 127 LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 128
mluis 0:62d1edcc13d1 129 // go from stanby to sleep
mluis 0:62d1edcc13d1 130 Radio.Sleep( );
mluis 0:62d1edcc13d1 131 // run os job (use preset func ptr)
mluis 0:62d1edcc13d1 132 os_setCallback( &LMIC.osjob, LMIC.osjob.func );
mluis 0:62d1edcc13d1 133 }
mluis 0:62d1edcc13d1 134
mluis 0:62d1edcc13d1 135 void OnRxError( void )
mluis 0:62d1edcc13d1 136 {
mluis 0:62d1edcc13d1 137 ostime_t now = os_getTime( );
mluis 0:62d1edcc13d1 138
mluis 0:62d1edcc13d1 139 // indicate error
mluis 0:62d1edcc13d1 140 LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 141
mluis 0:62d1edcc13d1 142 // go from stanby to sleep
mluis 0:62d1edcc13d1 143 Radio.Sleep( );
mluis 0:62d1edcc13d1 144 // run os job (use preset func ptr)
mluis 0:62d1edcc13d1 145 os_setCallback( &LMIC.osjob, LMIC.osjob.func );
mluis 0:62d1edcc13d1 146 }
mluis 0:62d1edcc13d1 147
mluis 0:62d1edcc13d1 148 /*!
mluis 0:62d1edcc13d1 149 * LMIC API implementation
mluis 0:62d1edcc13d1 150 */
mluis 0:62d1edcc13d1 151 // RADIO STATE
mluis 0:62d1edcc13d1 152 // (initialized by radio_init( ), used by radio_rand1( ))
mluis 0:62d1edcc13d1 153 static u1_t randbuf[16];
mluis 0:62d1edcc13d1 154
mluis 0:62d1edcc13d1 155 // get random seed from wideband noise rssi
mluis 0:62d1edcc13d1 156 void radio_init( void )
mluis 0:62d1edcc13d1 157 {
mluis 0:62d1edcc13d1 158 hal_disableIRQs( );
mluis 0:62d1edcc13d1 159
mluis 0:62d1edcc13d1 160 // seed 15-byte randomness via noise rssi
mluis 0:62d1edcc13d1 161 // Set LoRa modem ON
mluis 0:62d1edcc13d1 162 Radio.SetModem( MODEM_LORA );
mluis 0:62d1edcc13d1 163 // Disable LoRa modem interrupts
mluis 0:62d1edcc13d1 164 Radio.Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT |
mluis 0:62d1edcc13d1 165 RFLR_IRQFLAGS_RXDONE |
mluis 0:62d1edcc13d1 166 RFLR_IRQFLAGS_PAYLOADCRCERROR |
mluis 0:62d1edcc13d1 167 RFLR_IRQFLAGS_VALIDHEADER |
mluis 0:62d1edcc13d1 168 RFLR_IRQFLAGS_TXDONE |
mluis 0:62d1edcc13d1 169 RFLR_IRQFLAGS_CADDONE |
mluis 0:62d1edcc13d1 170 RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
mluis 0:62d1edcc13d1 171 RFLR_IRQFLAGS_CADDETECTED );
mluis 0:62d1edcc13d1 172
mluis 0:62d1edcc13d1 173 // Set radio in continuous reception
mluis 0:62d1edcc13d1 174 Radio.Rx( 0 );
mluis 0:62d1edcc13d1 175
mluis 0:62d1edcc13d1 176 for( int i = 1; i < 16; i++ )
mluis 0:62d1edcc13d1 177 {
mluis 0:62d1edcc13d1 178 for( int j = 0; j < 8; j++ )
mluis 0:62d1edcc13d1 179 {
mluis 0:62d1edcc13d1 180 u1_t b; // wait for two non-identical subsequent least-significant bits
mluis 0:62d1edcc13d1 181 while( ( b = Radio.Read( REG_LR_RSSIWIDEBAND ) & 0x01 ) == ( Radio.Read( REG_LR_RSSIWIDEBAND ) & 0x01 ) );
mluis 0:62d1edcc13d1 182 randbuf[i] = ( randbuf[i] << 1 ) | b;
mluis 0:62d1edcc13d1 183 }
mluis 0:62d1edcc13d1 184 }
mluis 0:62d1edcc13d1 185 randbuf[0] = 16; // set initial index
mluis 0:62d1edcc13d1 186
mluis 0:62d1edcc13d1 187 // Change LoRa modem SyncWord
mluis 0:62d1edcc13d1 188 Radio.Write( REG_LR_SYNCWORD, LORA_MAC_SYNCWORD );
mluis 0:62d1edcc13d1 189
mluis 0:62d1edcc13d1 190 Radio.Sleep( );
mluis 0:62d1edcc13d1 191
mluis 0:62d1edcc13d1 192 hal_enableIRQs( );
mluis 0:62d1edcc13d1 193 }
mluis 0:62d1edcc13d1 194
mluis 0:62d1edcc13d1 195 // return next random byte derived from seed buffer
mluis 0:62d1edcc13d1 196 // (buf[0] holds index of next byte to be returned)
mluis 0:62d1edcc13d1 197 u1_t radio_rand1( void )
mluis 0:62d1edcc13d1 198 {
mluis 0:62d1edcc13d1 199 u1_t i = randbuf[0];
mluis 0:62d1edcc13d1 200 ASSERT( i != 0 );
mluis 0:62d1edcc13d1 201 if( i == 16 )
mluis 0:62d1edcc13d1 202 {
mluis 0:62d1edcc13d1 203 os_aes( AES_ENC, randbuf, 16 ); // encrypt seed with any key
mluis 0:62d1edcc13d1 204 i = 0;
mluis 0:62d1edcc13d1 205 }
mluis 0:62d1edcc13d1 206 u1_t v = randbuf[i++];
mluis 0:62d1edcc13d1 207 randbuf[0] = i;
mluis 0:62d1edcc13d1 208 return v;
mluis 0:62d1edcc13d1 209 }
mluis 0:62d1edcc13d1 210
mluis 0:62d1edcc13d1 211 void os_radio( u1_t mode )
mluis 0:62d1edcc13d1 212 {
mluis 0:62d1edcc13d1 213 hal_disableIRQs( );
mluis 0:62d1edcc13d1 214 switch( mode )
mluis 0:62d1edcc13d1 215 {
mluis 0:62d1edcc13d1 216 case RADIO_RST:
mluis 0:62d1edcc13d1 217 // put radio to sleep
mluis 0:62d1edcc13d1 218 Radio.Sleep( );
mluis 0:62d1edcc13d1 219 break;
mluis 0:62d1edcc13d1 220
mluis 0:62d1edcc13d1 221 case RADIO_TX:
mluis 0:62d1edcc13d1 222 // transmit frame now
mluis 0:62d1edcc13d1 223 //ASSERT( Radio.GetState( ) == IDLE );
mluis 0:62d1edcc13d1 224
mluis 0:62d1edcc13d1 225 Radio.SetChannel( LMIC.freq );
mluis 0:62d1edcc13d1 226 if( getSf( LMIC.rps ) == FSK )
mluis 0:62d1edcc13d1 227 { // FSK modem
mluis 0:62d1edcc13d1 228 Radio.SetTxConfig( MODEM_FSK, LMIC.txpow, 25e3, 0, 50e3, 0, 5, false, true, 0, 0, false, 3e6 );
mluis 0:62d1edcc13d1 229 }
mluis 0:62d1edcc13d1 230 else
mluis 0:62d1edcc13d1 231 { // LoRa modem
mluis 0:62d1edcc13d1 232
mluis 0:62d1edcc13d1 233 Radio.SetTxConfig( MODEM_LORA, LMIC.txpow, 0, getBw( LMIC.rps ), getSf( LMIC.rps ) + 6, getCr( LMIC.rps ) + 1, 8, getIh( LMIC.rps ) ? true : false, ( getNocrc(LMIC.rps) == 0 ) ? true : false, 0, 0, false, 3e6 );
mluis 0:62d1edcc13d1 234 }
mluis 0:62d1edcc13d1 235
mluis 0:62d1edcc13d1 236 //starttx( ); // buf=LMIC.frame, len=LMIC.dataLen
mluis 0:62d1edcc13d1 237 Radio.Send( LMIC.frame, LMIC.dataLen );
mluis 0:62d1edcc13d1 238 break;
mluis 0:62d1edcc13d1 239
mluis 0:62d1edcc13d1 240 case RADIO_RX:
mluis 0:62d1edcc13d1 241 // receive frame now (exactly at rxtime)
mluis 0:62d1edcc13d1 242 //ASSERT( Radio.GetState( ) == IDLE );
mluis 0:62d1edcc13d1 243
mluis 0:62d1edcc13d1 244 Radio.SetChannel( LMIC.freq );
mluis 0:62d1edcc13d1 245 if( getSf( LMIC.rps ) == FSK )
mluis 0:62d1edcc13d1 246 { // FSK modem
mluis 0:62d1edcc13d1 247 //Radio.SetRxConfig( MODEM_FSK, 50e3, 50e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, false );
mluis 0:62d1edcc13d1 248 Radio.SetRxConfig( MODEM_FSK, 50e3, 50e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, true );
mluis 0:62d1edcc13d1 249 }
mluis 0:62d1edcc13d1 250 else
mluis 0:62d1edcc13d1 251 { // LoRa modem
mluis 0:62d1edcc13d1 252
mluis 0:62d1edcc13d1 253 Radio.SetRxConfig( MODEM_LORA, getBw( LMIC.rps ), getSf( LMIC.rps ) + 6, getCr( LMIC.rps ) + 1, 0, 8, LMIC.rxsyms, getIh( LMIC.rps ) ? true : false, getIh(LMIC.rps), ( getNocrc(LMIC.rps) == 0 ) ? true : false, 0, 0, true, false );
mluis 0:62d1edcc13d1 254 }
mluis 0:62d1edcc13d1 255
mluis 0:62d1edcc13d1 256 // now instruct the radio to receive
mluis 0:62d1edcc13d1 257 hal_waitUntil( LMIC.rxtime ); // busy wait until exact rx time
mluis 0:62d1edcc13d1 258
mluis 0:62d1edcc13d1 259 //startrx( RXMODE_SINGLE ); // buf = LMIC.frame, time = LMIC.rxtime, timeout=LMIC.rxsyms
mluis 0:62d1edcc13d1 260 if( getSf( LMIC.rps ) == FSK )
mluis 0:62d1edcc13d1 261 { // FSK modem
mluis 0:62d1edcc13d1 262 Radio.Rx( 50e3 ); // Max Rx window 50 ms
mluis 0:62d1edcc13d1 263 }
mluis 0:62d1edcc13d1 264 else
mluis 0:62d1edcc13d1 265 { // LoRa modem
mluis 0:62d1edcc13d1 266 Radio.Rx( 3e6 ); // Max Rx window 3 seconds
mluis 0:62d1edcc13d1 267 }
mluis 0:62d1edcc13d1 268 break;
mluis 0:62d1edcc13d1 269
mluis 0:62d1edcc13d1 270 case RADIO_RXON:
mluis 0:62d1edcc13d1 271 // start scanning for beacon now
mluis 0:62d1edcc13d1 272
mluis 0:62d1edcc13d1 273 //ASSERT( Radio.GetState( ) == IDLE );
mluis 0:62d1edcc13d1 274
mluis 0:62d1edcc13d1 275 Radio.SetChannel( LMIC.freq );
mluis 0:62d1edcc13d1 276 if( getSf( LMIC.rps ) == FSK )
mluis 0:62d1edcc13d1 277 { // FSK modem
mluis 0:62d1edcc13d1 278 Radio.SetRxConfig( MODEM_FSK, 50e3, 50e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, true );
mluis 0:62d1edcc13d1 279 }
mluis 0:62d1edcc13d1 280 else
mluis 0:62d1edcc13d1 281 { // LoRa modem
mluis 0:62d1edcc13d1 282 Radio.SetRxConfig( MODEM_LORA, getBw( LMIC.rps ), getSf( LMIC.rps ) + 6, getCr( LMIC.rps ) + 1, 0, 8, LMIC.rxsyms, getIh( LMIC.rps ) ? true : false, getIh(LMIC.rps), ( getNocrc(LMIC.rps) == 0 ) ? true : false, 0, 0, true, true );
mluis 0:62d1edcc13d1 283 }
mluis 0:62d1edcc13d1 284
mluis 0:62d1edcc13d1 285 //startrx( RXMODE_SCAN) ; // buf = LMIC.frame
mluis 0:62d1edcc13d1 286 Radio.Rx( 0 );
mluis 0:62d1edcc13d1 287 break;
mluis 0:62d1edcc13d1 288 }
mluis 0:62d1edcc13d1 289 hal_enableIRQs( );
mluis 0:62d1edcc13d1 290 }
mluis 0:62d1edcc13d1 291
mluis 0:62d1edcc13d1 292 #else
mluis 0:62d1edcc13d1 293
mluis 0:62d1edcc13d1 294 // ----------------------------------------
mluis 0:62d1edcc13d1 295 // Registers Mapping
mluis 0:62d1edcc13d1 296 #define RegFifo 0x00 // common
mluis 0:62d1edcc13d1 297 #define RegOpMode 0x01 // common
mluis 0:62d1edcc13d1 298 #define FSKRegBitrateMsb 0x02
mluis 0:62d1edcc13d1 299 #define FSKRegBitrateLsb 0x03
mluis 0:62d1edcc13d1 300 #define FSKRegFdevMsb 0x04
mluis 0:62d1edcc13d1 301 #define FSKRegFdevLsb 0x05
mluis 0:62d1edcc13d1 302 #define RegFrfMsb 0x06 // common
mluis 0:62d1edcc13d1 303 #define RegFrfMid 0x07 // common
mluis 0:62d1edcc13d1 304 #define RegFrfLsb 0x08 // common
mluis 0:62d1edcc13d1 305 #define RegPaConfig 0x09 // common
mluis 0:62d1edcc13d1 306 #define RegPaRamp 0x0A // common
mluis 0:62d1edcc13d1 307 #define RegOcp 0x0B // common
mluis 0:62d1edcc13d1 308 #define RegLna 0x0C // common
mluis 0:62d1edcc13d1 309 #define FSKRegRxConfig 0x0D
mluis 0:62d1edcc13d1 310 #define LORARegFifoAddrPtr 0x0D
mluis 0:62d1edcc13d1 311 #define FSKRegRssiConfig 0x0E
mluis 0:62d1edcc13d1 312 #define LORARegFifoTxBaseAddr 0x0E
mluis 0:62d1edcc13d1 313 #define FSKRegRssiCollision 0x0F
mluis 0:62d1edcc13d1 314 #define LORARegFifoRxBaseAddr 0x0F
mluis 0:62d1edcc13d1 315 #define FSKRegRssiThresh 0x10
mluis 0:62d1edcc13d1 316 #define LORARegFifoRxCurrentAddr 0x10
mluis 0:62d1edcc13d1 317 #define FSKRegRssiValue 0x11
mluis 0:62d1edcc13d1 318 #define LORARegIrqFlagsMask 0x11
mluis 0:62d1edcc13d1 319 #define FSKRegRxBw 0x12
mluis 0:62d1edcc13d1 320 #define LORARegIrqFlags 0x12
mluis 0:62d1edcc13d1 321 #define FSKRegAfcBw 0x13
mluis 0:62d1edcc13d1 322 #define LORARegRxNbBytes 0x13
mluis 0:62d1edcc13d1 323 #define FSKRegOokPeak 0x14
mluis 0:62d1edcc13d1 324 #define LORARegRxHeaderCntValueMsb 0x14
mluis 0:62d1edcc13d1 325 #define FSKRegOokFix 0x15
mluis 0:62d1edcc13d1 326 #define LORARegRxHeaderCntValueLsb 0x15
mluis 0:62d1edcc13d1 327 #define FSKRegOokAvg 0x16
mluis 0:62d1edcc13d1 328 #define LORARegRxPacketCntValueMsb 0x16
mluis 0:62d1edcc13d1 329 #define LORARegRxpacketCntValueLsb 0x17
mluis 0:62d1edcc13d1 330 #define LORARegModemStat 0x18
mluis 0:62d1edcc13d1 331 #define LORARegPktSnrValue 0x19
mluis 0:62d1edcc13d1 332 #define FSKRegAfcFei 0x1A
mluis 0:62d1edcc13d1 333 #define LORARegPktRssiValue 0x1A
mluis 0:62d1edcc13d1 334 #define FSKRegAfcMsb 0x1B
mluis 0:62d1edcc13d1 335 #define LORARegRssiValue 0x1B
mluis 0:62d1edcc13d1 336 #define FSKRegAfcLsb 0x1C
mluis 0:62d1edcc13d1 337 #define LORARegHopChannel 0x1C
mluis 0:62d1edcc13d1 338 #define FSKRegFeiMsb 0x1D
mluis 0:62d1edcc13d1 339 #define LORARegModemConfig1 0x1D
mluis 0:62d1edcc13d1 340 #define FSKRegFeiLsb 0x1E
mluis 0:62d1edcc13d1 341 #define LORARegModemConfig2 0x1E
mluis 0:62d1edcc13d1 342 #define FSKRegPreambleDetect 0x1F
mluis 0:62d1edcc13d1 343 #define LORARegSymbTimeoutLsb 0x1F
mluis 0:62d1edcc13d1 344 #define FSKRegRxTimeout1 0x20
mluis 0:62d1edcc13d1 345 #define LORARegPreambleMsb 0x20
mluis 0:62d1edcc13d1 346 #define FSKRegRxTimeout2 0x21
mluis 0:62d1edcc13d1 347 #define LORARegPreambleLsb 0x21
mluis 0:62d1edcc13d1 348 #define FSKRegRxTimeout3 0x22
mluis 0:62d1edcc13d1 349 #define LORARegPayloadLength 0x22
mluis 0:62d1edcc13d1 350 #define FSKRegRxDelay 0x23
mluis 0:62d1edcc13d1 351 #define LORARegPayloadMaxLength 0x23
mluis 0:62d1edcc13d1 352 #define FSKRegOsc 0x24
mluis 0:62d1edcc13d1 353 #define LORARegHopPeriod 0x24
mluis 0:62d1edcc13d1 354 #define FSKRegPreambleMsb 0x25
mluis 0:62d1edcc13d1 355 #define LORARegFifoRxByteAddr 0x25
mluis 0:62d1edcc13d1 356 #define LORARegModemConfig3 0x26
mluis 0:62d1edcc13d1 357 #define FSKRegPreambleLsb 0x26
mluis 0:62d1edcc13d1 358 #define FSKRegSyncConfig 0x27
mluis 0:62d1edcc13d1 359 #define LORARegFeiMsb 0x28
mluis 0:62d1edcc13d1 360 #define FSKRegSyncValue1 0x28
mluis 0:62d1edcc13d1 361 #define LORAFeiMib 0x29
mluis 0:62d1edcc13d1 362 #define FSKRegSyncValue2 0x29
mluis 0:62d1edcc13d1 363 #define LORARegFeiLsb 0x2A
mluis 0:62d1edcc13d1 364 #define FSKRegSyncValue3 0x2A
mluis 0:62d1edcc13d1 365 #define FSKRegSyncValue4 0x2B
mluis 0:62d1edcc13d1 366 #define LORARegRssiWideband 0x2C
mluis 0:62d1edcc13d1 367 #define FSKRegSyncValue5 0x2C
mluis 0:62d1edcc13d1 368 #define FSKRegSyncValue6 0x2D
mluis 0:62d1edcc13d1 369 #define FSKRegSyncValue7 0x2E
mluis 0:62d1edcc13d1 370 #define FSKRegSyncValue8 0x2F
mluis 0:62d1edcc13d1 371 #define FSKRegPacketConfig1 0x30
mluis 0:62d1edcc13d1 372 #define FSKRegPacketConfig2 0x31
mluis 0:62d1edcc13d1 373 #define LORARegDetectOptimize 0x31
mluis 0:62d1edcc13d1 374 #define FSKRegPayloadLength 0x32
mluis 0:62d1edcc13d1 375 #define FSKRegNodeAdrs 0x33
mluis 0:62d1edcc13d1 376 #define LORARegInvertIQ 0x33
mluis 0:62d1edcc13d1 377 #define FSKRegBroadcastAdrs 0x34
mluis 0:62d1edcc13d1 378 #define FSKRegFifoThresh 0x35
mluis 0:62d1edcc13d1 379 #define FSKRegSeqConfig1 0x36
mluis 0:62d1edcc13d1 380 #define FSKRegSeqConfig2 0x37
mluis 0:62d1edcc13d1 381 #define LORARegDetectionThreshold 0x37
mluis 0:62d1edcc13d1 382 #define FSKRegTimerResol 0x38
mluis 0:62d1edcc13d1 383 #define FSKRegTimer1Coef 0x39
mluis 0:62d1edcc13d1 384 #define LORARegSyncWord 0x39
mluis 0:62d1edcc13d1 385 #define FSKRegTimer2Coef 0x3A
mluis 0:62d1edcc13d1 386 #define FSKRegImageCal 0x3B
mluis 0:62d1edcc13d1 387 #define FSKRegTemp 0x3C
mluis 0:62d1edcc13d1 388 #define FSKRegLowBat 0x3D
mluis 0:62d1edcc13d1 389 #define FSKRegIrqFlags1 0x3E
mluis 0:62d1edcc13d1 390 #define FSKRegIrqFlags2 0x3F
mluis 0:62d1edcc13d1 391 #define RegDioMapping1 0x40 // common
mluis 0:62d1edcc13d1 392 #define RegDioMapping2 0x41 // common
mluis 0:62d1edcc13d1 393 #define RegVersion 0x42 // common
mluis 0:62d1edcc13d1 394 // #define RegAgcRef 0x43 // common
mluis 0:62d1edcc13d1 395 // #define RegAgcThresh1 0x44 // common
mluis 0:62d1edcc13d1 396 // #define RegAgcThresh2 0x45 // common
mluis 0:62d1edcc13d1 397 // #define RegAgcThresh3 0x46 // common
mluis 0:62d1edcc13d1 398 // #define RegPllHop 0x4B // common
mluis 0:62d1edcc13d1 399 // #define RegTcxo 0x58 // common
mluis 0:62d1edcc13d1 400 #define RegPaDac 0x5A // common
mluis 0:62d1edcc13d1 401 // #define RegPll 0x5C // common
mluis 0:62d1edcc13d1 402 // #define RegPllLowPn 0x5E // common
mluis 0:62d1edcc13d1 403 // #define RegFormerTemp 0x6C // common
mluis 0:62d1edcc13d1 404 // #define RegBitRateFrac 0x70 // common
mluis 0:62d1edcc13d1 405
mluis 0:62d1edcc13d1 406 // ----------------------------------------
mluis 0:62d1edcc13d1 407 // spread factors and mode for RegModemConfig2
mluis 0:62d1edcc13d1 408 #define SX1272_MC2_FSK 0x00
mluis 0:62d1edcc13d1 409 #define SX1272_MC2_SF7 0x70
mluis 0:62d1edcc13d1 410 #define SX1272_MC2_SF8 0x80
mluis 0:62d1edcc13d1 411 #define SX1272_MC2_SF9 0x90
mluis 0:62d1edcc13d1 412 #define SX1272_MC2_SF10 0xA0
mluis 0:62d1edcc13d1 413 #define SX1272_MC2_SF11 0xB0
mluis 0:62d1edcc13d1 414 #define SX1272_MC2_SF12 0xC0
mluis 0:62d1edcc13d1 415 // bandwidth for RegModemConfig1
mluis 0:62d1edcc13d1 416 #define SX1272_MC1_BW_125 0x00
mluis 0:62d1edcc13d1 417 #define SX1272_MC1_BW_250 0x40
mluis 0:62d1edcc13d1 418 #define SX1272_MC1_BW_500 0x80
mluis 0:62d1edcc13d1 419 // coding rate for RegModemConfig1
mluis 0:62d1edcc13d1 420 #define SX1272_MC1_CR_4_5 0x08
mluis 0:62d1edcc13d1 421 #define SX1272_MC1_CR_4_6 0x10
mluis 0:62d1edcc13d1 422 #define SX1272_MC1_CR_4_7 0x18
mluis 0:62d1edcc13d1 423 #define SX1272_MC1_CR_4_8 0x20
mluis 0:62d1edcc13d1 424 #define SX1272_MC1_IMPLICIT_HEADER_MODE_ON 0x04 // required for receive
mluis 0:62d1edcc13d1 425 #define SX1272_MC1_RX_PAYLOAD_CRCON 0x02
mluis 0:62d1edcc13d1 426 #define SX1272_MC1_LOW_DATA_RATE_OPTIMIZE 0x01 // mandated for SF11 and SF12
mluis 0:62d1edcc13d1 427 // transmit power configuration for RegPaConfig
mluis 0:62d1edcc13d1 428 #define SX1272_PAC_PA_SELECT_PA_BOOST 0x80
mluis 0:62d1edcc13d1 429 #define SX1272_PAC_PA_SELECT_RFIO_PIN 0x00
mluis 0:62d1edcc13d1 430
mluis 0:62d1edcc13d1 431
mluis 0:62d1edcc13d1 432 // sx1276 RegModemConfig1
mluis 0:62d1edcc13d1 433 #define SX1276_MC1_BW_125 0x70
mluis 0:62d1edcc13d1 434 #define SX1276_MC1_BW_250 0x80
mluis 0:62d1edcc13d1 435 #define SX1276_MC1_BW_500 0x90
mluis 0:62d1edcc13d1 436 #define SX1276_MC1_CR_4_5 0x02
mluis 0:62d1edcc13d1 437 #define SX1276_MC1_CR_4_6 0x04
mluis 0:62d1edcc13d1 438 #define SX1276_MC1_CR_4_7 0x06
mluis 0:62d1edcc13d1 439 #define SX1276_MC1_CR_4_8 0x08
mluis 0:62d1edcc13d1 440
mluis 0:62d1edcc13d1 441 #define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
mluis 0:62d1edcc13d1 442
mluis 0:62d1edcc13d1 443 // sx1276 RegModemConfig2
mluis 0:62d1edcc13d1 444 #define SX1276_MC2_RX_PAYLOAD_CRCON 0x04
mluis 0:62d1edcc13d1 445
mluis 0:62d1edcc13d1 446 // sx1276 RegModemConfig3
mluis 0:62d1edcc13d1 447 #define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE 0x08
mluis 0:62d1edcc13d1 448 #define SX1276_MC3_AGCAUTO 0x04
mluis 0:62d1edcc13d1 449
mluis 0:62d1edcc13d1 450 // preamble for lora networks (nibbles swapped)
mluis 0:62d1edcc13d1 451 #define LORA_MAC_PREAMBLE 0x34
mluis 0:62d1edcc13d1 452
mluis 0:62d1edcc13d1 453 #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1 0x0A
mluis 0:62d1edcc13d1 454 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 455 #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x70
mluis 0:62d1edcc13d1 456 #elif CFG_sx1272_radio
mluis 0:62d1edcc13d1 457 #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74
mluis 0:62d1edcc13d1 458 #endif
mluis 0:62d1edcc13d1 459
mluis 0:62d1edcc13d1 460
mluis 0:62d1edcc13d1 461
mluis 0:62d1edcc13d1 462 // ----------------------------------------
mluis 0:62d1edcc13d1 463 // Constants for radio registers
mluis 0:62d1edcc13d1 464 #define OPMODE_LORA 0x80
mluis 0:62d1edcc13d1 465 #define OPMODE_MASK 0x07
mluis 0:62d1edcc13d1 466 #define OPMODE_SLEEP 0x00
mluis 0:62d1edcc13d1 467 #define OPMODE_STANDBY 0x01
mluis 0:62d1edcc13d1 468 #define OPMODE_FSTX 0x02
mluis 0:62d1edcc13d1 469 #define OPMODE_TX 0x03
mluis 0:62d1edcc13d1 470 #define OPMODE_FSRX 0x04
mluis 0:62d1edcc13d1 471 #define OPMODE_RX 0x05
mluis 0:62d1edcc13d1 472 #define OPMODE_RX_SINGLE 0x06
mluis 0:62d1edcc13d1 473 #define OPMODE_CAD 0x07
mluis 0:62d1edcc13d1 474
mluis 0:62d1edcc13d1 475 // ----------------------------------------
mluis 0:62d1edcc13d1 476 // Bits masking the corresponding IRQs from the radio
mluis 0:62d1edcc13d1 477 #define IRQ_LORA_RXTOUT_MASK 0x80
mluis 0:62d1edcc13d1 478 #define IRQ_LORA_RXDONE_MASK 0x40
mluis 0:62d1edcc13d1 479 #define IRQ_LORA_CRCERR_MASK 0x20
mluis 0:62d1edcc13d1 480 #define IRQ_LORA_HEADER_MASK 0x10
mluis 0:62d1edcc13d1 481 #define IRQ_LORA_TXDONE_MASK 0x08
mluis 0:62d1edcc13d1 482 #define IRQ_LORA_CDDONE_MASK 0x04
mluis 0:62d1edcc13d1 483 #define IRQ_LORA_FHSSCH_MASK 0x02
mluis 0:62d1edcc13d1 484 #define IRQ_LORA_CDDETD_MASK 0x01
mluis 0:62d1edcc13d1 485
mluis 0:62d1edcc13d1 486 #define IRQ_FSK1_MODEREADY_MASK 0x80
mluis 0:62d1edcc13d1 487 #define IRQ_FSK1_RXREADY_MASK 0x40
mluis 0:62d1edcc13d1 488 #define IRQ_FSK1_TXREADY_MASK 0x20
mluis 0:62d1edcc13d1 489 #define IRQ_FSK1_PLLLOCK_MASK 0x10
mluis 0:62d1edcc13d1 490 #define IRQ_FSK1_RSSI_MASK 0x08
mluis 0:62d1edcc13d1 491 #define IRQ_FSK1_TIMEOUT_MASK 0x04
mluis 0:62d1edcc13d1 492 #define IRQ_FSK1_PREAMBLEDETECT_MASK 0x02
mluis 0:62d1edcc13d1 493 #define IRQ_FSK1_SYNCADDRESSMATCH_MASK 0x01
mluis 0:62d1edcc13d1 494 #define IRQ_FSK2_FIFOFULL_MASK 0x80
mluis 0:62d1edcc13d1 495 #define IRQ_FSK2_FIFOEMPTY_MASK 0x40
mluis 0:62d1edcc13d1 496 #define IRQ_FSK2_FIFOLEVEL_MASK 0x20
mluis 0:62d1edcc13d1 497 #define IRQ_FSK2_FIFOOVERRUN_MASK 0x10
mluis 0:62d1edcc13d1 498 #define IRQ_FSK2_PACKETSENT_MASK 0x08
mluis 0:62d1edcc13d1 499 #define IRQ_FSK2_PAYLOADREADY_MASK 0x04
mluis 0:62d1edcc13d1 500 #define IRQ_FSK2_CRCOK_MASK 0x02
mluis 0:62d1edcc13d1 501 #define IRQ_FSK2_LOWBAT_MASK 0x01
mluis 0:62d1edcc13d1 502
mluis 0:62d1edcc13d1 503 // ----------------------------------------
mluis 0:62d1edcc13d1 504 // DIO function mappings D0D1D2D3
mluis 0:62d1edcc13d1 505 #define MAP_DIO0_LORA_RXDONE 0x00 // 00------
mluis 0:62d1edcc13d1 506 #define MAP_DIO0_LORA_TXDONE 0x40 // 01------
mluis 0:62d1edcc13d1 507 #define MAP_DIO1_LORA_RXTOUT 0x00 // --00----
mluis 0:62d1edcc13d1 508 #define MAP_DIO1_LORA_NOP 0x30 // --11----
mluis 0:62d1edcc13d1 509 #define MAP_DIO2_LORA_NOP 0xC0 // ----11--
mluis 0:62d1edcc13d1 510
mluis 0:62d1edcc13d1 511 #define MAP_DIO0_FSK_READY 0x00 // 00------ (packet sent / payload ready)
mluis 0:62d1edcc13d1 512 #define MAP_DIO1_FSK_NOP 0x30 // --11----
mluis 0:62d1edcc13d1 513 #define MAP_DIO2_FSK_TXNOP 0x04 // ----01--
mluis 0:62d1edcc13d1 514 #define MAP_DIO2_FSK_TIMEOUT 0x08 // ----10--
mluis 0:62d1edcc13d1 515
mluis 0:62d1edcc13d1 516
mluis 0:62d1edcc13d1 517 // FSK IMAGECAL defines
mluis 0:62d1edcc13d1 518 #define RF_IMAGECAL_AUTOIMAGECAL_MASK 0x7F
mluis 0:62d1edcc13d1 519 #define RF_IMAGECAL_AUTOIMAGECAL_ON 0x80
mluis 0:62d1edcc13d1 520 #define RF_IMAGECAL_AUTOIMAGECAL_OFF 0x00 // Default
mluis 0:62d1edcc13d1 521
mluis 0:62d1edcc13d1 522 #define RF_IMAGECAL_IMAGECAL_MASK 0xBF
mluis 0:62d1edcc13d1 523 #define RF_IMAGECAL_IMAGECAL_START 0x40
mluis 0:62d1edcc13d1 524
mluis 0:62d1edcc13d1 525 #define RF_IMAGECAL_IMAGECAL_RUNNING 0x20
mluis 0:62d1edcc13d1 526 #define RF_IMAGECAL_IMAGECAL_DONE 0x00 // Default
mluis 0:62d1edcc13d1 527
mluis 0:62d1edcc13d1 528
mluis 0:62d1edcc13d1 529 // RADIO STATE
mluis 0:62d1edcc13d1 530 // (initialized by radio_init(), used by radio_rand1())
mluis 0:62d1edcc13d1 531 static u1_t randbuf[16];
mluis 0:62d1edcc13d1 532
mluis 0:62d1edcc13d1 533
mluis 0:62d1edcc13d1 534 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 535 #define LNA_RX_GAIN (0x20|0x1)
mluis 0:62d1edcc13d1 536 #elif CFG_sx1272_radio
mluis 0:62d1edcc13d1 537 #define LNA_RX_GAIN (0x20|0x03)
mluis 0:62d1edcc13d1 538 #else
mluis 0:62d1edcc13d1 539 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
mluis 0:62d1edcc13d1 540 #endif
mluis 0:62d1edcc13d1 541
mluis 0:62d1edcc13d1 542 static void writeReg (u1_t addr, u1_t data ) {
mluis 0:62d1edcc13d1 543 hal_pin_nss(0);
mluis 0:62d1edcc13d1 544 hal_spi(addr | 0x80);
mluis 0:62d1edcc13d1 545 hal_spi(data);
mluis 0:62d1edcc13d1 546 hal_pin_nss(1);
mluis 0:62d1edcc13d1 547 }
mluis 0:62d1edcc13d1 548
mluis 0:62d1edcc13d1 549 static u1_t readReg (u1_t addr) {
mluis 0:62d1edcc13d1 550 hal_pin_nss(0);
mluis 0:62d1edcc13d1 551 hal_spi(addr & 0x7F);
mluis 0:62d1edcc13d1 552 u1_t val = hal_spi(0x00);
mluis 0:62d1edcc13d1 553 hal_pin_nss(1);
mluis 0:62d1edcc13d1 554 return val;
mluis 0:62d1edcc13d1 555 }
mluis 0:62d1edcc13d1 556
mluis 0:62d1edcc13d1 557 static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) {
mluis 0:62d1edcc13d1 558 hal_pin_nss(0);
mluis 0:62d1edcc13d1 559 hal_spi(addr | 0x80);
mluis 0:62d1edcc13d1 560 for (u1_t i=0; i<len; i++) {
mluis 0:62d1edcc13d1 561 hal_spi(buf[i]);
mluis 0:62d1edcc13d1 562 }
mluis 0:62d1edcc13d1 563 hal_pin_nss(1);
mluis 0:62d1edcc13d1 564 }
mluis 0:62d1edcc13d1 565
mluis 0:62d1edcc13d1 566 static void readBuf (u1_t addr, xref2u1_t buf, u1_t len) {
mluis 0:62d1edcc13d1 567 hal_pin_nss(0);
mluis 0:62d1edcc13d1 568 hal_spi(addr & 0x7F);
mluis 0:62d1edcc13d1 569 for (u1_t i=0; i<len; i++) {
mluis 0:62d1edcc13d1 570 buf[i] = hal_spi(0x00);
mluis 0:62d1edcc13d1 571 }
mluis 0:62d1edcc13d1 572 hal_pin_nss(1);
mluis 0:62d1edcc13d1 573 }
mluis 0:62d1edcc13d1 574
mluis 0:62d1edcc13d1 575 static void opmode (u1_t mode) {
mluis 0:62d1edcc13d1 576 writeReg(RegOpMode, (readReg(RegOpMode) & ~OPMODE_MASK) | mode);
mluis 0:62d1edcc13d1 577 }
mluis 0:62d1edcc13d1 578
mluis 0:62d1edcc13d1 579 static void opmodeLora(void) {
mluis 0:62d1edcc13d1 580 u1_t u = OPMODE_LORA;
mluis 0:62d1edcc13d1 581 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 582 u |= 0x8; // TBD: sx1276 high freq
mluis 0:62d1edcc13d1 583 #endif
mluis 0:62d1edcc13d1 584 writeReg(RegOpMode, u);
mluis 0:62d1edcc13d1 585 }
mluis 0:62d1edcc13d1 586
mluis 0:62d1edcc13d1 587 static void opmodeFSK(void) {
mluis 0:62d1edcc13d1 588 u1_t u = 0;
mluis 0:62d1edcc13d1 589 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 590 u |= 0x8; // TBD: sx1276 high freq
mluis 0:62d1edcc13d1 591 #endif
mluis 0:62d1edcc13d1 592 writeReg(RegOpMode, u);
mluis 0:62d1edcc13d1 593 }
mluis 0:62d1edcc13d1 594
mluis 0:62d1edcc13d1 595 // configure LoRa modem (cfg1, cfg2)
mluis 0:62d1edcc13d1 596 static void configLoraModem (void) {
mluis 0:62d1edcc13d1 597 sf_t sf = getSf(LMIC.rps);
mluis 0:62d1edcc13d1 598
mluis 0:62d1edcc13d1 599 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 600 u1_t mc1 = 0, mc2 = 0, mc3 = 0;
mluis 0:62d1edcc13d1 601
mluis 0:62d1edcc13d1 602 switch (getBw(LMIC.rps)) {
mluis 0:62d1edcc13d1 603 case BW125: mc1 |= SX1276_MC1_BW_125; break;
mluis 0:62d1edcc13d1 604 case BW250: mc1 |= SX1276_MC1_BW_250; break;
mluis 0:62d1edcc13d1 605 case BW500: mc1 |= SX1276_MC1_BW_500; break;
mluis 0:62d1edcc13d1 606 default:
mluis 0:62d1edcc13d1 607 ASSERT(0);
mluis 0:62d1edcc13d1 608 }
mluis 0:62d1edcc13d1 609 switch( getCr(LMIC.rps) ) {
mluis 0:62d1edcc13d1 610 case CR_4_5: mc1 |= SX1276_MC1_CR_4_5; break;
mluis 0:62d1edcc13d1 611 case CR_4_6: mc1 |= SX1276_MC1_CR_4_6; break;
mluis 0:62d1edcc13d1 612 case CR_4_7: mc1 |= SX1276_MC1_CR_4_7; break;
mluis 0:62d1edcc13d1 613 case CR_4_8: mc1 |= SX1276_MC1_CR_4_8; break;
mluis 0:62d1edcc13d1 614 default:
mluis 0:62d1edcc13d1 615 ASSERT(0);
mluis 0:62d1edcc13d1 616 }
mluis 0:62d1edcc13d1 617
mluis 0:62d1edcc13d1 618 if (getIh(LMIC.rps)) {
mluis 0:62d1edcc13d1 619 mc1 |= SX1276_MC1_IMPLICIT_HEADER_MODE_ON;
mluis 0:62d1edcc13d1 620 writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
mluis 0:62d1edcc13d1 621 }
mluis 0:62d1edcc13d1 622 // set ModemConfig1
mluis 0:62d1edcc13d1 623 writeReg(LORARegModemConfig1, mc1);
mluis 0:62d1edcc13d1 624
mluis 0:62d1edcc13d1 625 mc2 = (SX1272_MC2_SF7 + ((sf-1)<<4));
mluis 0:62d1edcc13d1 626 if (getNocrc(LMIC.rps) == 0) {
mluis 0:62d1edcc13d1 627 mc2 |= SX1276_MC2_RX_PAYLOAD_CRCON;
mluis 0:62d1edcc13d1 628 }
mluis 0:62d1edcc13d1 629 writeReg(LORARegModemConfig2, mc2);
mluis 0:62d1edcc13d1 630
mluis 0:62d1edcc13d1 631 mc3 = SX1276_MC3_AGCAUTO;
mluis 0:62d1edcc13d1 632 if (sf == SF11 || sf == SF12) {
mluis 0:62d1edcc13d1 633 mc3 |= SX1276_MC3_LOW_DATA_RATE_OPTIMIZE;
mluis 0:62d1edcc13d1 634 }
mluis 0:62d1edcc13d1 635 writeReg(LORARegModemConfig3, mc3);
mluis 0:62d1edcc13d1 636 #elif CFG_sx1272_radio
mluis 0:62d1edcc13d1 637 u1_t mc1 = (getBw(LMIC.rps)<<6);
mluis 0:62d1edcc13d1 638
mluis 0:62d1edcc13d1 639 switch( getCr(LMIC.rps) ) {
mluis 0:62d1edcc13d1 640 case CR_4_5: mc1 |= SX1272_MC1_CR_4_5; break;
mluis 0:62d1edcc13d1 641 case CR_4_6: mc1 |= SX1272_MC1_CR_4_6; break;
mluis 0:62d1edcc13d1 642 case CR_4_7: mc1 |= SX1272_MC1_CR_4_7; break;
mluis 0:62d1edcc13d1 643 case CR_4_8: mc1 |= SX1272_MC1_CR_4_8; break;
mluis 0:62d1edcc13d1 644 }
mluis 0:62d1edcc13d1 645
mluis 0:62d1edcc13d1 646 if (sf == SF11 || sf == SF12) {
mluis 0:62d1edcc13d1 647 mc1 |= SX1272_MC1_LOW_DATA_RATE_OPTIMIZE;
mluis 0:62d1edcc13d1 648 }
mluis 0:62d1edcc13d1 649
mluis 0:62d1edcc13d1 650 if (getNocrc(LMIC.rps) == 0) {
mluis 0:62d1edcc13d1 651 mc1 |= SX1272_MC1_RX_PAYLOAD_CRCON;
mluis 0:62d1edcc13d1 652 }
mluis 0:62d1edcc13d1 653
mluis 0:62d1edcc13d1 654 if (getIh(LMIC.rps)) {
mluis 0:62d1edcc13d1 655 mc1 |= SX1272_MC1_IMPLICIT_HEADER_MODE_ON;
mluis 0:62d1edcc13d1 656 writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
mluis 0:62d1edcc13d1 657 }
mluis 0:62d1edcc13d1 658 // set ModemConfig1
mluis 0:62d1edcc13d1 659 writeReg(LORARegModemConfig1, mc1);
mluis 0:62d1edcc13d1 660
mluis 0:62d1edcc13d1 661 // set ModemConfig2 (sf, AgcAutoOn=1 SymbTimeoutHi=00)
mluis 0:62d1edcc13d1 662 writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x04);
mluis 0:62d1edcc13d1 663 #else
mluis 0:62d1edcc13d1 664 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
mluis 0:62d1edcc13d1 665 #endif /* CFG_sx1272_radio */
mluis 0:62d1edcc13d1 666 }
mluis 0:62d1edcc13d1 667
mluis 0:62d1edcc13d1 668 static void configChannel (void) {
mluis 0:62d1edcc13d1 669 // set frequency: FQ = (FRF * 32 Mhz) / (2 ^ 19)
mluis 0:62d1edcc13d1 670 u8_t frf = ((u8_t)LMIC.freq << 19) / 32000000;
mluis 0:62d1edcc13d1 671 writeReg(RegFrfMsb, (u1_t)(frf>>16));
mluis 0:62d1edcc13d1 672 writeReg(RegFrfMid, (u1_t)(frf>> 8));
mluis 0:62d1edcc13d1 673 writeReg(RegFrfLsb, (u1_t)(frf>> 0));
mluis 0:62d1edcc13d1 674 }
mluis 0:62d1edcc13d1 675
mluis 0:62d1edcc13d1 676
mluis 0:62d1edcc13d1 677
mluis 0:62d1edcc13d1 678 static void configPower (void) {
mluis 0:62d1edcc13d1 679 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 680 // no boost used for now
mluis 0:62d1edcc13d1 681 s1_t pw = (s1_t)LMIC.txpow;
mluis 0:62d1edcc13d1 682 if(pw > 14) {
mluis 0:62d1edcc13d1 683 pw = 14;
mluis 0:62d1edcc13d1 684 } else if(pw < -1) {
mluis 0:62d1edcc13d1 685 pw = -1;
mluis 0:62d1edcc13d1 686 }
mluis 0:62d1edcc13d1 687 // check board type for BOOST pin
mluis 0:62d1edcc13d1 688 writeReg(RegPaConfig, (u1_t)(0x00|((pw+1)&0xf)));
mluis 0:62d1edcc13d1 689 writeReg(RegPaDac, readReg(RegPaDac)|0x4);
mluis 0:62d1edcc13d1 690
mluis 0:62d1edcc13d1 691 #elif CFG_sx1272_radio
mluis 0:62d1edcc13d1 692 // set PA config (2-17 dBm using PA_BOOST)
mluis 0:62d1edcc13d1 693 s1_t pw = (s1_t)LMIC.txpow;
mluis 0:62d1edcc13d1 694 if(pw > 17) {
mluis 0:62d1edcc13d1 695 pw = 17;
mluis 0:62d1edcc13d1 696 } else if(pw < 2) {
mluis 0:62d1edcc13d1 697 pw = 2;
mluis 0:62d1edcc13d1 698 }
mluis 0:62d1edcc13d1 699 writeReg(RegPaConfig, (u1_t)(0x80|(pw-2)));
mluis 0:62d1edcc13d1 700 #else
mluis 0:62d1edcc13d1 701 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
mluis 0:62d1edcc13d1 702 #endif /* CFG_sx1272_radio */
mluis 0:62d1edcc13d1 703 }
mluis 0:62d1edcc13d1 704
mluis 0:62d1edcc13d1 705 static void txfsk (void) {
mluis 0:62d1edcc13d1 706 // select FSK modem (from sleep mode)
mluis 0:62d1edcc13d1 707 writeReg(RegOpMode, 0x10); // FSK, BT=0.5
mluis 0:62d1edcc13d1 708 ASSERT(readReg(RegOpMode) == 0x10);
mluis 0:62d1edcc13d1 709 // enter standby mode (required for FIFO loading))
mluis 0:62d1edcc13d1 710 opmode(OPMODE_STANDBY);
mluis 0:62d1edcc13d1 711 // set bitrate
mluis 0:62d1edcc13d1 712 writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
mluis 0:62d1edcc13d1 713 writeReg(FSKRegBitrateLsb, 0x80);
mluis 0:62d1edcc13d1 714 // set frequency deviation
mluis 0:62d1edcc13d1 715 writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
mluis 0:62d1edcc13d1 716 writeReg(FSKRegFdevLsb, 0x99);
mluis 0:62d1edcc13d1 717 // frame and packet handler settings
mluis 0:62d1edcc13d1 718 writeReg(FSKRegPreambleMsb, 0x00);
mluis 0:62d1edcc13d1 719 writeReg(FSKRegPreambleLsb, 0x05);
mluis 0:62d1edcc13d1 720 writeReg(FSKRegSyncConfig, 0x12);
mluis 0:62d1edcc13d1 721 writeReg(FSKRegPacketConfig1, 0xD0);
mluis 0:62d1edcc13d1 722 writeReg(FSKRegPacketConfig2, 0x40);
mluis 0:62d1edcc13d1 723 writeReg(FSKRegSyncValue1, 0xC1);
mluis 0:62d1edcc13d1 724 writeReg(FSKRegSyncValue2, 0x94);
mluis 0:62d1edcc13d1 725 writeReg(FSKRegSyncValue3, 0xC1);
mluis 0:62d1edcc13d1 726 // configure frequency
mluis 0:62d1edcc13d1 727 configChannel();
mluis 0:62d1edcc13d1 728 // configure output power
mluis 0:62d1edcc13d1 729 configPower();
mluis 0:62d1edcc13d1 730
mluis 0:62d1edcc13d1 731 // set the IRQ mapping DIO0=PacketSent DIO1=NOP DIO2=NOP
mluis 0:62d1edcc13d1 732 writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TXNOP);
mluis 0:62d1edcc13d1 733
mluis 0:62d1edcc13d1 734 // initialize the payload size and address pointers
mluis 0:62d1edcc13d1 735 writeReg(FSKRegPayloadLength, LMIC.dataLen+1); // (insert length byte into payload))
mluis 0:62d1edcc13d1 736
mluis 0:62d1edcc13d1 737 // download length byte and buffer to the radio FIFO
mluis 0:62d1edcc13d1 738 writeReg(RegFifo, LMIC.dataLen);
mluis 0:62d1edcc13d1 739 writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
mluis 0:62d1edcc13d1 740
mluis 0:62d1edcc13d1 741 // enable antenna switch for TX
mluis 0:62d1edcc13d1 742 hal_pin_rxtx(1);
mluis 0:62d1edcc13d1 743
mluis 0:62d1edcc13d1 744 // now we actually start the transmission
mluis 0:62d1edcc13d1 745 opmode(OPMODE_TX);
mluis 0:62d1edcc13d1 746 }
mluis 0:62d1edcc13d1 747
mluis 0:62d1edcc13d1 748 static void txlora (void) {
mluis 0:62d1edcc13d1 749 // select LoRa modem (from sleep mode)
mluis 0:62d1edcc13d1 750 //writeReg(RegOpMode, OPMODE_LORA);
mluis 0:62d1edcc13d1 751 opmodeLora();
mluis 0:62d1edcc13d1 752 ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
mluis 0:62d1edcc13d1 753
mluis 0:62d1edcc13d1 754 // enter standby mode (required for FIFO loading))
mluis 0:62d1edcc13d1 755 opmode(OPMODE_STANDBY);
mluis 0:62d1edcc13d1 756 // configure LoRa modem (cfg1, cfg2)
mluis 0:62d1edcc13d1 757 configLoraModem();
mluis 0:62d1edcc13d1 758 // configure frequency
mluis 0:62d1edcc13d1 759 configChannel();
mluis 0:62d1edcc13d1 760 // configure output power
mluis 0:62d1edcc13d1 761 writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec
mluis 0:62d1edcc13d1 762 configPower();
mluis 0:62d1edcc13d1 763 // set sync word
mluis 0:62d1edcc13d1 764 writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
mluis 0:62d1edcc13d1 765
mluis 0:62d1edcc13d1 766 // set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
mluis 0:62d1edcc13d1 767 writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP);
mluis 0:62d1edcc13d1 768 // clear all radio IRQ flags
mluis 0:62d1edcc13d1 769 writeReg(LORARegIrqFlags, 0xFF);
mluis 0:62d1edcc13d1 770 // mask all IRQs but TxDone
mluis 0:62d1edcc13d1 771 writeReg(LORARegIrqFlagsMask, ~IRQ_LORA_TXDONE_MASK);
mluis 0:62d1edcc13d1 772
mluis 0:62d1edcc13d1 773 // initialize the payload size and address pointers
mluis 0:62d1edcc13d1 774 writeReg(LORARegFifoTxBaseAddr, 0x00);
mluis 0:62d1edcc13d1 775 writeReg(LORARegFifoAddrPtr, 0x00);
mluis 0:62d1edcc13d1 776 writeReg(LORARegPayloadLength, LMIC.dataLen);
mluis 0:62d1edcc13d1 777
mluis 0:62d1edcc13d1 778 // download buffer to the radio FIFO
mluis 0:62d1edcc13d1 779 writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
mluis 0:62d1edcc13d1 780
mluis 0:62d1edcc13d1 781 // enable antenna switch for TX
mluis 0:62d1edcc13d1 782 hal_pin_rxtx(1);
mluis 0:62d1edcc13d1 783
mluis 0:62d1edcc13d1 784 // now we actually start the transmission
mluis 0:62d1edcc13d1 785 opmode(OPMODE_TX);
mluis 0:62d1edcc13d1 786 }
mluis 0:62d1edcc13d1 787
mluis 0:62d1edcc13d1 788 // start transmitter (buf=LMIC.frame, len=LMIC.dataLen)
mluis 0:62d1edcc13d1 789 static void starttx (void) {
mluis 0:62d1edcc13d1 790 ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
mluis 0:62d1edcc13d1 791 if(getSf(LMIC.rps) == FSK) { // FSK modem
mluis 0:62d1edcc13d1 792 txfsk();
mluis 0:62d1edcc13d1 793 } else { // LoRa modem
mluis 0:62d1edcc13d1 794 txlora();
mluis 0:62d1edcc13d1 795 }
mluis 0:62d1edcc13d1 796 // the radio will go back to STANDBY mode as soon as the TX is finished
mluis 0:62d1edcc13d1 797 // the corresponding IRQ will inform us about completion.
mluis 0:62d1edcc13d1 798 }
mluis 0:62d1edcc13d1 799
mluis 0:62d1edcc13d1 800 enum { RXMODE_SINGLE, RXMODE_SCAN, RXMODE_RSSI };
mluis 0:62d1edcc13d1 801
mluis 0:62d1edcc13d1 802 static const u1_t rxlorairqmask[] = {
mluis 0:62d1edcc13d1 803 [RXMODE_SINGLE] = IRQ_LORA_RXDONE_MASK|IRQ_LORA_RXTOUT_MASK,
mluis 0:62d1edcc13d1 804 [RXMODE_SCAN] = IRQ_LORA_RXDONE_MASK,
mluis 0:62d1edcc13d1 805 [RXMODE_RSSI] = 0x00,
mluis 0:62d1edcc13d1 806 };
mluis 0:62d1edcc13d1 807
mluis 0:62d1edcc13d1 808 // start LoRa receiver (time=LMIC.rxtime, timeout=LMIC.rxsyms, result=LMIC.frame[LMIC.dataLen])
mluis 0:62d1edcc13d1 809 static void rxlora (u1_t rxmode) {
mluis 0:62d1edcc13d1 810 // select LoRa modem (from sleep mode)
mluis 0:62d1edcc13d1 811 opmodeLora();
mluis 0:62d1edcc13d1 812 ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
mluis 0:62d1edcc13d1 813 // enter standby mode (warm up))
mluis 0:62d1edcc13d1 814 opmode(OPMODE_STANDBY);
mluis 0:62d1edcc13d1 815 // don't use MAC settings at startup
mluis 0:62d1edcc13d1 816 if(rxmode == RXMODE_RSSI) { // use fixed settings for rssi scan
mluis 0:62d1edcc13d1 817 writeReg(LORARegModemConfig1, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1);
mluis 0:62d1edcc13d1 818 writeReg(LORARegModemConfig2, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2);
mluis 0:62d1edcc13d1 819 } else { // single or continuous rx mode
mluis 0:62d1edcc13d1 820 // configure LoRa modem (cfg1, cfg2)
mluis 0:62d1edcc13d1 821 configLoraModem();
mluis 0:62d1edcc13d1 822 // configure frequency
mluis 0:62d1edcc13d1 823 configChannel();
mluis 0:62d1edcc13d1 824 }
mluis 0:62d1edcc13d1 825 // set LNA gain
mluis 0:62d1edcc13d1 826 writeReg(RegLna, LNA_RX_GAIN);
mluis 0:62d1edcc13d1 827 // set max payload size
mluis 0:62d1edcc13d1 828 writeReg(LORARegPayloadMaxLength, 64);
mluis 0:62d1edcc13d1 829 // use inverted I/Q signal (prevent mote-to-mote communication)
mluis 0:62d1edcc13d1 830 writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ)|(1<<6));
mluis 0:62d1edcc13d1 831 // set symbol timeout (for single rx)
mluis 0:62d1edcc13d1 832 writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms);
mluis 0:62d1edcc13d1 833 // set sync word
mluis 0:62d1edcc13d1 834 writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
mluis 0:62d1edcc13d1 835
mluis 0:62d1edcc13d1 836 // configure DIO mapping DIO0=RxDone DIO1=RxTout DIO2=NOP
mluis 0:62d1edcc13d1 837 writeReg(RegDioMapping1, MAP_DIO0_LORA_RXDONE|MAP_DIO1_LORA_RXTOUT|MAP_DIO2_LORA_NOP);
mluis 0:62d1edcc13d1 838 // clear all radio IRQ flags
mluis 0:62d1edcc13d1 839 writeReg(LORARegIrqFlags, 0xFF);
mluis 0:62d1edcc13d1 840 // enable required radio IRQs
mluis 0:62d1edcc13d1 841 writeReg(LORARegIrqFlagsMask, ~rxlorairqmask[rxmode]);
mluis 0:62d1edcc13d1 842
mluis 0:62d1edcc13d1 843 // enable antenna switch for RX
mluis 0:62d1edcc13d1 844 hal_pin_rxtx(0);
mluis 0:62d1edcc13d1 845
mluis 0:62d1edcc13d1 846 // now instruct the radio to receive
mluis 0:62d1edcc13d1 847 if (rxmode == RXMODE_SINGLE) { // single rx
mluis 0:62d1edcc13d1 848 hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
mluis 0:62d1edcc13d1 849 opmode(OPMODE_RX_SINGLE);
mluis 0:62d1edcc13d1 850 } else { // continous rx (scan or rssi)
mluis 0:62d1edcc13d1 851 opmode(OPMODE_RX);
mluis 0:62d1edcc13d1 852 }
mluis 0:62d1edcc13d1 853 }
mluis 0:62d1edcc13d1 854
mluis 0:62d1edcc13d1 855 static void rxfsk (u1_t rxmode) {
mluis 0:62d1edcc13d1 856 // only single rx (no continuous scanning, no noise sampling)
mluis 0:62d1edcc13d1 857 ASSERT( rxmode == RXMODE_SINGLE );
mluis 0:62d1edcc13d1 858 // select FSK modem (from sleep mode)
mluis 0:62d1edcc13d1 859 //writeReg(RegOpMode, 0x00); // (not LoRa)
mluis 0:62d1edcc13d1 860 opmodeFSK();
mluis 0:62d1edcc13d1 861 ASSERT((readReg(RegOpMode) & OPMODE_LORA) == 0);
mluis 0:62d1edcc13d1 862 // enter standby mode (warm up))
mluis 0:62d1edcc13d1 863 opmode(OPMODE_STANDBY);
mluis 0:62d1edcc13d1 864 // configure frequency
mluis 0:62d1edcc13d1 865 configChannel();
mluis 0:62d1edcc13d1 866 // set LNA gain
mluis 0:62d1edcc13d1 867 //writeReg(RegLna, 0x20|0x03); // max gain, boost enable
mluis 0:62d1edcc13d1 868 writeReg(RegLna, LNA_RX_GAIN);
mluis 0:62d1edcc13d1 869 // configure receiver
mluis 0:62d1edcc13d1 870 writeReg(FSKRegRxConfig, 0x1E); // AFC auto, AGC, trigger on preamble?!?
mluis 0:62d1edcc13d1 871 // set receiver bandwidth
mluis 0:62d1edcc13d1 872 writeReg(FSKRegRxBw, 0x0B); // 50kHz SSb
mluis 0:62d1edcc13d1 873 // set AFC bandwidth
mluis 0:62d1edcc13d1 874 writeReg(FSKRegAfcBw, 0x12); // 83.3kHz SSB
mluis 0:62d1edcc13d1 875 // set preamble detection
mluis 0:62d1edcc13d1 876 writeReg(FSKRegPreambleDetect, 0xAA); // enable, 2 bytes, 10 chip errors
mluis 0:62d1edcc13d1 877 // set sync config
mluis 0:62d1edcc13d1 878 writeReg(FSKRegSyncConfig, 0x12); // no auto restart, preamble 0xAA, enable, fill FIFO, 3 bytes sync
mluis 0:62d1edcc13d1 879 // set packet config
mluis 0:62d1edcc13d1 880 writeReg(FSKRegPacketConfig1, 0xD8); // var-length, whitening, crc, no auto-clear, no adr filter
mluis 0:62d1edcc13d1 881 writeReg(FSKRegPacketConfig2, 0x40); // packet mode
mluis 0:62d1edcc13d1 882 // set sync value
mluis 0:62d1edcc13d1 883 writeReg(FSKRegSyncValue1, 0xC1);
mluis 0:62d1edcc13d1 884 writeReg(FSKRegSyncValue2, 0x94);
mluis 0:62d1edcc13d1 885 writeReg(FSKRegSyncValue3, 0xC1);
mluis 0:62d1edcc13d1 886 // set preamble timeout
mluis 0:62d1edcc13d1 887 writeReg(FSKRegRxTimeout2, 0xFF);//(LMIC.rxsyms+1)/2);
mluis 0:62d1edcc13d1 888 // set bitrate
mluis 0:62d1edcc13d1 889 writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
mluis 0:62d1edcc13d1 890 writeReg(FSKRegBitrateLsb, 0x80);
mluis 0:62d1edcc13d1 891 // set frequency deviation
mluis 0:62d1edcc13d1 892 writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
mluis 0:62d1edcc13d1 893 writeReg(FSKRegFdevLsb, 0x99);
mluis 0:62d1edcc13d1 894
mluis 0:62d1edcc13d1 895 // configure DIO mapping DIO0=PayloadReady DIO1=NOP DIO2=TimeOut
mluis 0:62d1edcc13d1 896 writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TIMEOUT);
mluis 0:62d1edcc13d1 897
mluis 0:62d1edcc13d1 898 // enable antenna switch for RX
mluis 0:62d1edcc13d1 899 hal_pin_rxtx(0);
mluis 0:62d1edcc13d1 900
mluis 0:62d1edcc13d1 901 // now instruct the radio to receive
mluis 0:62d1edcc13d1 902 hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
mluis 0:62d1edcc13d1 903 opmode(OPMODE_RX); // no single rx mode available in FSK
mluis 0:62d1edcc13d1 904 }
mluis 0:62d1edcc13d1 905
mluis 0:62d1edcc13d1 906 static void startrx (u1_t rxmode) {
mluis 0:62d1edcc13d1 907 ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
mluis 0:62d1edcc13d1 908 if(getSf(LMIC.rps) == FSK) { // FSK modem
mluis 0:62d1edcc13d1 909 rxfsk(rxmode);
mluis 0:62d1edcc13d1 910 } else { // LoRa modem
mluis 0:62d1edcc13d1 911 rxlora(rxmode);
mluis 0:62d1edcc13d1 912 }
mluis 0:62d1edcc13d1 913 // the radio will go back to STANDBY mode as soon as the RX is finished
mluis 0:62d1edcc13d1 914 // or timed out, and the corresponding IRQ will inform us about completion.
mluis 0:62d1edcc13d1 915 }
mluis 0:62d1edcc13d1 916
mluis 0:62d1edcc13d1 917 // get random seed from wideband noise rssi
mluis 0:62d1edcc13d1 918 void radio_init (void) {
mluis 0:62d1edcc13d1 919 hal_disableIRQs();
mluis 0:62d1edcc13d1 920
mluis 0:62d1edcc13d1 921 // manually reset radio
mluis 0:62d1edcc13d1 922 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 923 hal_pin_rst(0); // drive RST pin low
mluis 0:62d1edcc13d1 924 #else
mluis 0:62d1edcc13d1 925 hal_pin_rst(1); // drive RST pin high
mluis 0:62d1edcc13d1 926 #endif
mluis 0:62d1edcc13d1 927 hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us
mluis 0:62d1edcc13d1 928 hal_pin_rst(2); // configure RST pin floating!
mluis 0:62d1edcc13d1 929 hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms
mluis 0:62d1edcc13d1 930
mluis 0:62d1edcc13d1 931 opmode(OPMODE_SLEEP);
mluis 0:62d1edcc13d1 932 // some sanity checks, e.g., read version number
mluis 0:62d1edcc13d1 933 u1_t v = readReg(RegVersion);
mluis 0:62d1edcc13d1 934 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 935 ASSERT(v == 0x12 );
mluis 0:62d1edcc13d1 936 #elif CFG_sx1272_radio
mluis 0:62d1edcc13d1 937 ASSERT(v == 0x22);
mluis 0:62d1edcc13d1 938 #else
mluis 0:62d1edcc13d1 939 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
mluis 0:62d1edcc13d1 940 #endif
mluis 0:62d1edcc13d1 941 // seed 15-byte randomness via noise rssi
mluis 0:62d1edcc13d1 942 rxlora(RXMODE_RSSI);
mluis 0:62d1edcc13d1 943 while( (readReg(RegOpMode) & OPMODE_MASK) != OPMODE_RX ); // continuous rx
mluis 0:62d1edcc13d1 944 for(int i=1; i<16; i++) {
mluis 0:62d1edcc13d1 945 for(int j=0; j<8; j++) {
mluis 0:62d1edcc13d1 946 u1_t b; // wait for two non-identical subsequent least-significant bits
mluis 0:62d1edcc13d1 947 while( (b = readReg(LORARegRssiWideband) & 0x01) == (readReg(LORARegRssiWideband) & 0x01) );
mluis 0:62d1edcc13d1 948 randbuf[i] = (randbuf[i] << 1) | b;
mluis 0:62d1edcc13d1 949 }
mluis 0:62d1edcc13d1 950 }
mluis 0:62d1edcc13d1 951 randbuf[0] = 16; // set initial index
mluis 0:62d1edcc13d1 952
mluis 0:62d1edcc13d1 953 #ifdef CFG_sx1276_radio
mluis 0:62d1edcc13d1 954 // chain calibration
mluis 0:62d1edcc13d1 955 writeReg(RegPaConfig, 0);
mluis 0:62d1edcc13d1 956
mluis 0:62d1edcc13d1 957 // Launch Rx chain calibration for LF band
mluis 0:62d1edcc13d1 958 writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
mluis 0:62d1edcc13d1 959 while((readReg(FSKRegImageCal)&RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING){ ; }
mluis 0:62d1edcc13d1 960
mluis 0:62d1edcc13d1 961 // Sets a Frequency in HF band
mluis 0:62d1edcc13d1 962 u4_t frf = 868000000;
mluis 0:62d1edcc13d1 963 writeReg(RegFrfMsb, (u1_t)(frf>>16));
mluis 0:62d1edcc13d1 964 writeReg(RegFrfMid, (u1_t)(frf>> 8));
mluis 0:62d1edcc13d1 965 writeReg(RegFrfLsb, (u1_t)(frf>> 0));
mluis 0:62d1edcc13d1 966
mluis 0:62d1edcc13d1 967 // Launch Rx chain calibration for HF band
mluis 0:62d1edcc13d1 968 writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
mluis 0:62d1edcc13d1 969 while((readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING) { ; }
mluis 0:62d1edcc13d1 970 #endif /* CFG_sx1276_radio */
mluis 0:62d1edcc13d1 971
mluis 0:62d1edcc13d1 972 opmode(OPMODE_SLEEP);
mluis 0:62d1edcc13d1 973 hal_enableIRQs();
mluis 0:62d1edcc13d1 974 }
mluis 0:62d1edcc13d1 975
mluis 0:62d1edcc13d1 976 // return next random byte derived from seed buffer
mluis 0:62d1edcc13d1 977 // (buf[0] holds index of next byte to be returned)
mluis 0:62d1edcc13d1 978 u1_t radio_rand1 (void) {
mluis 0:62d1edcc13d1 979 u1_t i = randbuf[0];
mluis 0:62d1edcc13d1 980 ASSERT( i != 0 );
mluis 0:62d1edcc13d1 981 if( i==16 ) {
mluis 0:62d1edcc13d1 982 os_aes(AES_ENC, randbuf, 16); // encrypt seed with any key
mluis 0:62d1edcc13d1 983 i = 0;
mluis 0:62d1edcc13d1 984 }
mluis 0:62d1edcc13d1 985 u1_t v = randbuf[i++];
mluis 0:62d1edcc13d1 986 randbuf[0] = i;
mluis 0:62d1edcc13d1 987 return v;
mluis 0:62d1edcc13d1 988 }
mluis 0:62d1edcc13d1 989
mluis 0:62d1edcc13d1 990 u1_t radio_rssi (void) {
mluis 0:62d1edcc13d1 991 hal_disableIRQs();
mluis 0:62d1edcc13d1 992 u1_t r = readReg(LORARegRssiValue);
mluis 0:62d1edcc13d1 993 hal_enableIRQs();
mluis 0:62d1edcc13d1 994 return r;
mluis 0:62d1edcc13d1 995 }
mluis 0:62d1edcc13d1 996
mluis 0:62d1edcc13d1 997 static const u2_t LORA_RXDONE_FIXUP[] = {
mluis 0:62d1edcc13d1 998 [FSK] = us2osticks(0), // ( 0 ticks)
mluis 0:62d1edcc13d1 999 [SF7] = us2osticks(0), // ( 0 ticks)
mluis 0:62d1edcc13d1 1000 [SF8] = us2osticks(1648), // ( 54 ticks)
mluis 0:62d1edcc13d1 1001 [SF9] = us2osticks(3265), // ( 107 ticks)
mluis 0:62d1edcc13d1 1002 [SF10] = us2osticks(7049), // ( 231 ticks)
mluis 0:62d1edcc13d1 1003 [SF11] = us2osticks(13641), // ( 447 ticks)
mluis 0:62d1edcc13d1 1004 [SF12] = us2osticks(31189), // (1022 ticks)
mluis 0:62d1edcc13d1 1005 };
mluis 0:62d1edcc13d1 1006
mluis 0:62d1edcc13d1 1007 // called by hal ext IRQ handler
mluis 0:62d1edcc13d1 1008 // (radio goes to stanby mode after tx/rx operations)
mluis 0:62d1edcc13d1 1009 void radio_irq_handler (u1_t dio) {
mluis 0:62d1edcc13d1 1010 ostime_t now = os_getTime();
mluis 0:62d1edcc13d1 1011 if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem
mluis 0:62d1edcc13d1 1012 u1_t flags = readReg(LORARegIrqFlags);
mluis 0:62d1edcc13d1 1013 if( flags & IRQ_LORA_TXDONE_MASK ) {
mluis 0:62d1edcc13d1 1014 // save exact tx time
mluis 0:62d1edcc13d1 1015 LMIC.txend = now - us2osticks(43); // TXDONE FIXUP
mluis 0:62d1edcc13d1 1016 } else if( flags & IRQ_LORA_RXDONE_MASK ) {
mluis 0:62d1edcc13d1 1017 // save exact rx time
mluis 0:62d1edcc13d1 1018 LMIC.rxtime = now - LORA_RXDONE_FIXUP[getSf(LMIC.rps)];
mluis 0:62d1edcc13d1 1019 // read the PDU and inform the MAC that we received something
mluis 0:62d1edcc13d1 1020 LMIC.dataLen = (readReg(LORARegModemConfig1) & SX1272_MC1_IMPLICIT_HEADER_MODE_ON) ?
mluis 0:62d1edcc13d1 1021 readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes);
mluis 0:62d1edcc13d1 1022 // set FIFO read address pointer
mluis 0:62d1edcc13d1 1023 writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr));
mluis 0:62d1edcc13d1 1024 // now read the FIFO
mluis 0:62d1edcc13d1 1025 readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
mluis 0:62d1edcc13d1 1026 // read rx quality parameters
mluis 0:62d1edcc13d1 1027 LMIC.rxq.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
mluis 0:62d1edcc13d1 1028 LMIC.rxq.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63)
mluis 0:62d1edcc13d1 1029 } else if( flags & IRQ_LORA_RXTOUT_MASK ) {
mluis 0:62d1edcc13d1 1030 // indicate timeout
mluis 0:62d1edcc13d1 1031 LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 1032 }
mluis 0:62d1edcc13d1 1033 // mask all radio IRQs
mluis 0:62d1edcc13d1 1034 writeReg(LORARegIrqFlagsMask, 0xFF);
mluis 0:62d1edcc13d1 1035 // clear radio IRQ flags
mluis 0:62d1edcc13d1 1036 writeReg(LORARegIrqFlags, 0xFF);
mluis 0:62d1edcc13d1 1037 } else { // FSK modem
mluis 0:62d1edcc13d1 1038 u1_t flags1 = readReg(FSKRegIrqFlags1);
mluis 0:62d1edcc13d1 1039 u1_t flags2 = readReg(FSKRegIrqFlags2);
mluis 0:62d1edcc13d1 1040 if( flags2 & IRQ_FSK2_PACKETSENT_MASK ) {
mluis 0:62d1edcc13d1 1041 // save exact tx time
mluis 0:62d1edcc13d1 1042 LMIC.txend = now;
mluis 0:62d1edcc13d1 1043 } else if( flags2 & IRQ_FSK2_PAYLOADREADY_MASK ) {
mluis 0:62d1edcc13d1 1044 // save exact rx time
mluis 0:62d1edcc13d1 1045 LMIC.rxtime = now;
mluis 0:62d1edcc13d1 1046 // read the PDU and inform the MAC that we received something
mluis 0:62d1edcc13d1 1047 LMIC.dataLen = readReg(FSKRegPayloadLength);
mluis 0:62d1edcc13d1 1048 // now read the FIFO
mluis 0:62d1edcc13d1 1049 readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
mluis 0:62d1edcc13d1 1050 // read rx quality parameters
mluis 0:62d1edcc13d1 1051 LMIC.rxq.snr = 0; // determine snr
mluis 0:62d1edcc13d1 1052 LMIC.rxq.rssi = 0; // determine rssi
mluis 0:62d1edcc13d1 1053 } else if( flags1 & IRQ_FSK1_TIMEOUT_MASK ) {
mluis 0:62d1edcc13d1 1054 // indicate timeout
mluis 0:62d1edcc13d1 1055 LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 1056 } else {
mluis 0:62d1edcc13d1 1057 while(1);
mluis 0:62d1edcc13d1 1058 }
mluis 0:62d1edcc13d1 1059 }
mluis 0:62d1edcc13d1 1060 // go from stanby to sleep
mluis 0:62d1edcc13d1 1061 opmode(OPMODE_SLEEP);
mluis 0:62d1edcc13d1 1062 // run os job (use preset func ptr)
mluis 0:62d1edcc13d1 1063 os_setCallback(&LMIC.osjob, LMIC.osjob.func);
mluis 0:62d1edcc13d1 1064 }
mluis 0:62d1edcc13d1 1065
mluis 0:62d1edcc13d1 1066 void os_radio (u1_t mode) {
mluis 0:62d1edcc13d1 1067 hal_disableIRQs();
mluis 0:62d1edcc13d1 1068 switch (mode) {
mluis 0:62d1edcc13d1 1069 case RADIO_RST:
mluis 0:62d1edcc13d1 1070 // put radio to sleep
mluis 0:62d1edcc13d1 1071 opmode(OPMODE_SLEEP);
mluis 0:62d1edcc13d1 1072 break;
mluis 0:62d1edcc13d1 1073
mluis 0:62d1edcc13d1 1074 case RADIO_TX:
mluis 0:62d1edcc13d1 1075 // transmit frame now
mluis 0:62d1edcc13d1 1076 starttx(); // buf=LMIC.frame, len=LMIC.dataLen
mluis 0:62d1edcc13d1 1077 break;
mluis 0:62d1edcc13d1 1078
mluis 0:62d1edcc13d1 1079 case RADIO_RX:
mluis 0:62d1edcc13d1 1080 // receive frame now (exactly at rxtime)
mluis 0:62d1edcc13d1 1081 startrx(RXMODE_SINGLE); // buf=LMIC.frame, time=LMIC.rxtime, timeout=LMIC.rxsyms
mluis 0:62d1edcc13d1 1082 break;
mluis 0:62d1edcc13d1 1083
mluis 0:62d1edcc13d1 1084 case RADIO_RXON:
mluis 0:62d1edcc13d1 1085 // start scanning for beacon now
mluis 0:62d1edcc13d1 1086 startrx(RXMODE_SCAN); // buf=LMIC.frame
mluis 0:62d1edcc13d1 1087 break;
mluis 0:62d1edcc13d1 1088 }
mluis 0:62d1edcc13d1 1089 hal_enableIRQs();
mluis 0:62d1edcc13d1 1090 }
mluis 0:62d1edcc13d1 1091
mluis 0:62d1edcc13d1 1092 #endif // USE_SMTC_RADIO_DRIVER