Example implementation of LoraWan specification based on IBM LoraWan in C (ver. 1.5) for Elmo board. Tested only with OTA activation (requires setting AppEui/ DevKey in main.cpp).
hal.cpp@0:bb3b0e756578, 2015-10-02 (annotated)
- Committer:
- WGorniak
- Date:
- Fri Oct 02 16:43:13 2015 +0200
- Revision:
- 0:bb3b0e756578
first commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WGorniak | 0:bb3b0e756578 | 1 | /******************************************************************************* |
WGorniak | 0:bb3b0e756578 | 2 | * Copyright (c) 2014 IBM Corporation. |
WGorniak | 0:bb3b0e756578 | 3 | * All rights reserved. This program and the accompanying materials |
WGorniak | 0:bb3b0e756578 | 4 | * are made available under the terms of the Eclipse Public License v1.0 |
WGorniak | 0:bb3b0e756578 | 5 | * which accompanies this distribution, and is available at |
WGorniak | 0:bb3b0e756578 | 6 | * http://www.eclipse.org/legal/epl-v10.html |
WGorniak | 0:bb3b0e756578 | 7 | * |
WGorniak | 0:bb3b0e756578 | 8 | * Contributors: |
WGorniak | 0:bb3b0e756578 | 9 | * IBM Zurich Research Lab - initial API, implementation and documentation |
WGorniak | 0:bb3b0e756578 | 10 | * Semtech Apps Team - Modified to support the MBED sx1276 driver |
WGorniak | 0:bb3b0e756578 | 11 | * library. |
WGorniak | 0:bb3b0e756578 | 12 | * Possibility to use original or Semtech's MBED |
WGorniak | 0:bb3b0e756578 | 13 | * radio driver. The selection is done by setting |
WGorniak | 0:bb3b0e756578 | 14 | * USE_SMTC_RADIO_DRIVER preprocessing directive |
WGorniak | 0:bb3b0e756578 | 15 | * in lmic.h |
WGorniak | 0:bb3b0e756578 | 16 | *******************************************************************************/ |
WGorniak | 0:bb3b0e756578 | 17 | #include "mbed.h" |
WGorniak | 0:bb3b0e756578 | 18 | #include "lmic.h" |
WGorniak | 0:bb3b0e756578 | 19 | #include "mbed_debug.h" |
WGorniak | 0:bb3b0e756578 | 20 | |
WGorniak | 0:bb3b0e756578 | 21 | #if !USE_SMTC_RADIO_DRIVER |
WGorniak | 0:bb3b0e756578 | 22 | |
WGorniak | 0:bb3b0e756578 | 23 | extern void radio_irq_handler( u1_t dio ); |
WGorniak | 0:bb3b0e756578 | 24 | |
WGorniak | 0:bb3b0e756578 | 25 | static DigitalOut nss( D10 ); |
WGorniak | 0:bb3b0e756578 | 26 | static SPI spi( D11, D12, D13 ); // ( mosi, miso, sclk ) |
WGorniak | 0:bb3b0e756578 | 27 | |
WGorniak | 0:bb3b0e756578 | 28 | static DigitalInOut rst( A0 ); |
WGorniak | 0:bb3b0e756578 | 29 | static DigitalOut rxtx( A4 ); |
WGorniak | 0:bb3b0e756578 | 30 | |
WGorniak | 0:bb3b0e756578 | 31 | static InterruptIn dio0( D2 ); |
WGorniak | 0:bb3b0e756578 | 32 | static InterruptIn dio1( D3 ); |
WGorniak | 0:bb3b0e756578 | 33 | static InterruptIn dio2( D4 ); |
WGorniak | 0:bb3b0e756578 | 34 | |
WGorniak | 0:bb3b0e756578 | 35 | static void dio0Irq( void ) { |
WGorniak | 0:bb3b0e756578 | 36 | radio_irq_handler( 0 ); |
WGorniak | 0:bb3b0e756578 | 37 | } |
WGorniak | 0:bb3b0e756578 | 38 | |
WGorniak | 0:bb3b0e756578 | 39 | static void dio1Irq( void ) { |
WGorniak | 0:bb3b0e756578 | 40 | radio_irq_handler( 1 ); |
WGorniak | 0:bb3b0e756578 | 41 | } |
WGorniak | 0:bb3b0e756578 | 42 | |
WGorniak | 0:bb3b0e756578 | 43 | static void dio2Irq( void ) { |
WGorniak | 0:bb3b0e756578 | 44 | radio_irq_handler( 2 ); |
WGorniak | 0:bb3b0e756578 | 45 | } |
WGorniak | 0:bb3b0e756578 | 46 | |
WGorniak | 0:bb3b0e756578 | 47 | #endif |
WGorniak | 0:bb3b0e756578 | 48 | |
WGorniak | 0:bb3b0e756578 | 49 | static u1_t irqlevel = 0; |
WGorniak | 0:bb3b0e756578 | 50 | static u4_t ticks = 0; |
WGorniak | 0:bb3b0e756578 | 51 | |
WGorniak | 0:bb3b0e756578 | 52 | static Timer timer; |
WGorniak | 0:bb3b0e756578 | 53 | static Ticker ticker; |
WGorniak | 0:bb3b0e756578 | 54 | |
WGorniak | 0:bb3b0e756578 | 55 | static void reset_timer( void ) { |
WGorniak | 0:bb3b0e756578 | 56 | ticks += timer.read_us( ) >> 6; |
WGorniak | 0:bb3b0e756578 | 57 | timer.reset( ); |
WGorniak | 0:bb3b0e756578 | 58 | } |
WGorniak | 0:bb3b0e756578 | 59 | |
WGorniak | 0:bb3b0e756578 | 60 | void hal_init( void ) { |
WGorniak | 0:bb3b0e756578 | 61 | __disable_irq( ); |
WGorniak | 0:bb3b0e756578 | 62 | irqlevel = 0; |
WGorniak | 0:bb3b0e756578 | 63 | |
WGorniak | 0:bb3b0e756578 | 64 | #if !USE_SMTC_RADIO_DRIVER |
WGorniak | 0:bb3b0e756578 | 65 | // configure input lines |
WGorniak | 0:bb3b0e756578 | 66 | dio0.mode( PullDown ); |
WGorniak | 0:bb3b0e756578 | 67 | dio0.rise( dio0Irq ); |
WGorniak | 0:bb3b0e756578 | 68 | dio0.enable_irq( ); |
WGorniak | 0:bb3b0e756578 | 69 | dio1.mode( PullDown ); |
WGorniak | 0:bb3b0e756578 | 70 | dio1.rise( dio1Irq ); |
WGorniak | 0:bb3b0e756578 | 71 | dio1.enable_irq( ); |
WGorniak | 0:bb3b0e756578 | 72 | dio2.mode( PullDown ); |
WGorniak | 0:bb3b0e756578 | 73 | dio2.rise( dio2Irq ); |
WGorniak | 0:bb3b0e756578 | 74 | dio2.enable_irq( ); |
WGorniak | 0:bb3b0e756578 | 75 | // configure reset line |
WGorniak | 0:bb3b0e756578 | 76 | rst.input( ); |
WGorniak | 0:bb3b0e756578 | 77 | // configure spi |
WGorniak | 0:bb3b0e756578 | 78 | spi.frequency( 8000000 ); |
WGorniak | 0:bb3b0e756578 | 79 | spi.format( 8, 0 ); |
WGorniak | 0:bb3b0e756578 | 80 | nss = 1; |
WGorniak | 0:bb3b0e756578 | 81 | #endif |
WGorniak | 0:bb3b0e756578 | 82 | // configure timer |
WGorniak | 0:bb3b0e756578 | 83 | timer.start( ); |
WGorniak | 0:bb3b0e756578 | 84 | ticker.attach_us( reset_timer, 10000000 ); // reset timer every 10sec |
WGorniak | 0:bb3b0e756578 | 85 | __enable_irq( ); |
WGorniak | 0:bb3b0e756578 | 86 | } |
WGorniak | 0:bb3b0e756578 | 87 | |
WGorniak | 0:bb3b0e756578 | 88 | #if !USE_SMTC_RADIO_DRIVER |
WGorniak | 0:bb3b0e756578 | 89 | |
WGorniak | 0:bb3b0e756578 | 90 | void hal_pin_rxtx( u1_t val ) { |
WGorniak | 0:bb3b0e756578 | 91 | rxtx = !val; |
WGorniak | 0:bb3b0e756578 | 92 | } |
WGorniak | 0:bb3b0e756578 | 93 | |
WGorniak | 0:bb3b0e756578 | 94 | void hal_pin_nss( u1_t val ) { |
WGorniak | 0:bb3b0e756578 | 95 | nss = val; |
WGorniak | 0:bb3b0e756578 | 96 | } |
WGorniak | 0:bb3b0e756578 | 97 | |
WGorniak | 0:bb3b0e756578 | 98 | void hal_pin_rst( u1_t val ) { |
WGorniak | 0:bb3b0e756578 | 99 | if( val == 0 || val == 1 ) |
WGorniak | 0:bb3b0e756578 | 100 | { // drive pin |
WGorniak | 0:bb3b0e756578 | 101 | rst.output( ); |
WGorniak | 0:bb3b0e756578 | 102 | rst = val; |
WGorniak | 0:bb3b0e756578 | 103 | } |
WGorniak | 0:bb3b0e756578 | 104 | else |
WGorniak | 0:bb3b0e756578 | 105 | { // keep pin floating |
WGorniak | 0:bb3b0e756578 | 106 | rst.input( ); |
WGorniak | 0:bb3b0e756578 | 107 | } |
WGorniak | 0:bb3b0e756578 | 108 | } |
WGorniak | 0:bb3b0e756578 | 109 | |
WGorniak | 0:bb3b0e756578 | 110 | u1_t hal_spi( u1_t out ) { |
WGorniak | 0:bb3b0e756578 | 111 | return spi.write( out ); |
WGorniak | 0:bb3b0e756578 | 112 | } |
WGorniak | 0:bb3b0e756578 | 113 | |
WGorniak | 0:bb3b0e756578 | 114 | #endif |
WGorniak | 0:bb3b0e756578 | 115 | |
WGorniak | 0:bb3b0e756578 | 116 | void hal_disableIRQs( void ) { |
WGorniak | 0:bb3b0e756578 | 117 | __disable_irq( ); |
WGorniak | 0:bb3b0e756578 | 118 | irqlevel++; |
WGorniak | 0:bb3b0e756578 | 119 | } |
WGorniak | 0:bb3b0e756578 | 120 | |
WGorniak | 0:bb3b0e756578 | 121 | void hal_enableIRQs( void ) { |
WGorniak | 0:bb3b0e756578 | 122 | if( --irqlevel == 0 ) |
WGorniak | 0:bb3b0e756578 | 123 | { |
WGorniak | 0:bb3b0e756578 | 124 | __enable_irq( ); |
WGorniak | 0:bb3b0e756578 | 125 | } |
WGorniak | 0:bb3b0e756578 | 126 | } |
WGorniak | 0:bb3b0e756578 | 127 | |
WGorniak | 0:bb3b0e756578 | 128 | void hal_sleep( void ) { |
WGorniak | 0:bb3b0e756578 | 129 | // NOP |
WGorniak | 0:bb3b0e756578 | 130 | } |
WGorniak | 0:bb3b0e756578 | 131 | |
WGorniak | 0:bb3b0e756578 | 132 | u4_t hal_ticks( void ) { |
WGorniak | 0:bb3b0e756578 | 133 | hal_disableIRQs( ); |
WGorniak | 0:bb3b0e756578 | 134 | int t = ticks + ( timer.read_us( ) >> 6 ); |
WGorniak | 0:bb3b0e756578 | 135 | hal_enableIRQs( ); |
WGorniak | 0:bb3b0e756578 | 136 | return t; |
WGorniak | 0:bb3b0e756578 | 137 | } |
WGorniak | 0:bb3b0e756578 | 138 | |
WGorniak | 0:bb3b0e756578 | 139 | static u2_t deltaticks( u4_t time ) { |
WGorniak | 0:bb3b0e756578 | 140 | u4_t t = hal_ticks( ); |
WGorniak | 0:bb3b0e756578 | 141 | s4_t d = time - t; |
WGorniak | 0:bb3b0e756578 | 142 | if( d <= 0 ) { |
WGorniak | 0:bb3b0e756578 | 143 | return 0; // in the past |
WGorniak | 0:bb3b0e756578 | 144 | } |
WGorniak | 0:bb3b0e756578 | 145 | if( ( d >> 16 ) != 0 ) { |
WGorniak | 0:bb3b0e756578 | 146 | return 0xFFFF; // far ahead |
WGorniak | 0:bb3b0e756578 | 147 | } |
WGorniak | 0:bb3b0e756578 | 148 | return ( u2_t )d; |
WGorniak | 0:bb3b0e756578 | 149 | } |
WGorniak | 0:bb3b0e756578 | 150 | |
WGorniak | 0:bb3b0e756578 | 151 | void hal_waitUntil( u4_t time ) { |
WGorniak | 0:bb3b0e756578 | 152 | while( deltaticks( time ) != 0 ); // busy wait until timestamp is reached |
WGorniak | 0:bb3b0e756578 | 153 | } |
WGorniak | 0:bb3b0e756578 | 154 | |
WGorniak | 0:bb3b0e756578 | 155 | u1_t hal_checkTimer( u4_t time ) { |
WGorniak | 0:bb3b0e756578 | 156 | return ( deltaticks( time ) < 2 ); |
WGorniak | 0:bb3b0e756578 | 157 | } |
WGorniak | 0:bb3b0e756578 | 158 | |
WGorniak | 0:bb3b0e756578 | 159 | void hal_failed( void ) { |
WGorniak | 0:bb3b0e756578 | 160 | while( 1 ); |
WGorniak | 0:bb3b0e756578 | 161 | } |