Semtech / LMiC

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

hal/hal.cpp

Committer:
mluis
Date:
2015-01-22
Revision:
0:62d1edcc13d1

File content as of revision 0:62d1edcc13d1:

/*******************************************************************************
 * Copyright (c) 2014 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
 *    Semtech Apps Team       - Modified to support the MBED sx1276 driver
 *                              library.
 *                              Possibility to use original or Semtech's MBED
 *                              radio driver. The selection is done by setting
 *                              USE_SMTC_RADIO_DRIVER preprocessing directive
 *                              in lmic.h
 *******************************************************************************/
#include "mbed.h"
#include "lmic.h"
#include "mbed_debug.h"

#if USE_SMTC_RADIO_DRIVER

#else

extern void radio_irq_handler( u1_t dio );

static DigitalOut nss( D10 );
static SPI spi( D11, D12, D13 ); // ( mosi, miso, sclk )
 
static DigitalInOut rst( A0 );
static DigitalOut rxtx( A4 );
 
static InterruptIn dio0( D2 );
static InterruptIn dio1( D3 );
static InterruptIn dio2( D4 ); 

static void dio0Irq( void )
{
    radio_irq_handler( 0 );
}

static void dio1Irq( void )
{
    radio_irq_handler( 1 );
}
static void dio2Irq( void )
{
    radio_irq_handler( 2 );
}

#endif

static u1_t irqlevel = 0;
static u4_t ticks = 0;

static Timer timer;
static Ticker ticker;

static void reset_timer( void )
{
    ticks += timer.read_us( ) >> 6;
    timer.reset( );
}

void hal_init( void )
{
     __disable_irq( );
     irqlevel = 0;

#if USE_SMTC_RADIO_DRIVER

#else
    // configure input lines
    dio0.mode( PullDown );
    dio0.rise( dio0Irq );
    dio0.enable_irq( );
    dio1.mode( PullDown );   
    dio1.rise( dio1Irq );
    dio1.enable_irq( );
    dio2.mode( PullDown );
    dio2.rise( dio2Irq );
    dio2.enable_irq( );
    // configure reset line
    rst.input( );
    // configure spi
    spi.frequency( 8000000 );
    spi.format( 8, 0 );
    nss = 1;
#endif
    // configure timer
    timer.start( );
    ticker.attach_us( reset_timer, 10000000 ); // reset timer every 10sec
     __enable_irq( );
}

#if USE_SMTC_RADIO_DRIVER

#else

void hal_pin_rxtx( u1_t val )
{
    rxtx = !val;
}

void hal_pin_nss( u1_t val )
{
    nss = val;
}

void hal_pin_rst( u1_t val )
{
    if( val == 0 || val == 1 )
    { // drive pin
        rst.output( );
        rst = val;
    } 
    else
    { // keep pin floating
        rst.input( );
    }
}

u1_t hal_spi( u1_t out )
{
    return spi.write( out );
}

#endif

void hal_disableIRQs( void )
{
    __disable_irq( );
    irqlevel++;
}

void hal_enableIRQs( void )
{
    if( --irqlevel == 0 )
    {
        __enable_irq( );
    }
}

void hal_sleep( void )
{
    // NOP
}

u4_t hal_ticks( void )
{
    hal_disableIRQs( );
    int t = ticks + ( timer.read_us( ) >> 6 );
    hal_enableIRQs( );
    return t;
}

static u2_t deltaticks( u4_t time )
{
    u4_t t = hal_ticks( );
    s4_t d = time - t;
    if( d <= 0 )
    {
        return 0;    // in the past
    }
    if( ( d >> 16 ) != 0 )
    {
        return 0xFFFF; // far ahead
    }
    return ( u2_t )d;
}

void hal_waitUntil( u4_t time )
{
    while( deltaticks( time ) != 0 ); // busy wait until timestamp is reached
}

u1_t hal_checkTimer( u4_t time )
{
    return ( deltaticks( time ) < 2 );
}

void hal_failed( void )
{
    while( 1 );
}

//////////////////////////////////////////////////////////////////////
// DEBUG CODE BELOW (use CFG_DEBUG)
//////////////////////////////////////////////////////////////////////
#ifdef CFG_DEBUG

void debug_init( void )
{
    // print banner
    debug( "\r\n============== DEBUG STARTED ==============\r\n" );
}

void debug_char( u1_t c )
{
    debug( "%c", c );
}

void debug_hex( u1_t b )
{
    debug( "%02X", b );
}

void debug_buf( const u1_t* buf, u2_t len )
{
    while( len-- )
    {
        debug_hex( *buf++ );
        debug_char( ' ' );
    }
    debug_char( '\r' );
    debug_char( '\n' );
}

void debug_uint( u4_t v )
{
    for( s1_t n = 24; n >= 0; n -= 8 )
    {
        debug_hex( v >> n );
    }
}

void debug_str( const u1_t* str )
{
    while( *str )
    {
        debug_char( *str++ );
    }
}

void debug_val( const u1_t* label, u4_t val )
{
    debug_str( label );
    debug_uint( val );
    debug_char( '\r' );
    debug_char( '\n' );
}

void debug_led( u1_t val )
{
    debug_val( "LED = ", val );
}

void debug_event( int ev ) 
{
    static const u1_t* evnames[] = 
    {
        [EV_SCAN_TIMEOUT]   = "SCAN_TIMEOUT",
        [EV_BEACON_FOUND]   = "BEACON_FOUND",
        [EV_BEACON_MISSED]  = "BEACON_MISSED",
        [EV_BEACON_TRACKED] = "BEACON_TRACKED",
        [EV_JOINING]        = "JOINING",
        [EV_JOINED]         = "JOINED",
        [EV_RFU1]           = "RFU1",
        [EV_JOIN_FAILED]    = "JOIN_FAILED",
        [EV_REJOIN_FAILED]  = "REJOIN_FAILED",
        [EV_TXCOMPLETE]     = "TXCOMPLETE",
        [EV_LOST_TSYNC]     = "LOST_TSYNC",
        [EV_RESET]          = "RESET",
        [EV_RXCOMPLETE]     = "RXCOMPLETE",
        [EV_LINK_DEAD]      = "LINK_DEAD",
        [EV_LINK_ALIVE]     = "LINK_ALIVE",
    };
    debug( "%s\r\n", evnames[ev] );
}
#endif // CFG_DEBUG