end node on synchronous star LoRa network.
Dependencies: SX127x sx12xx_hal TSL2561
radio chip selection
Radio chip driver is not included, allowing choice of radio device.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
if you're using SX1280, then import sx1280 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.
This project for use with LoRaWAN_singlechannel_gateway project.
Alternately gateway running on raspberry pi can be used as gateway.
LoRaWAN on single radio channel
Network description is at gateway project page. Synchronous star network.
Hardware Support
This project supports SX1276 and SX1272, sx126x kit, sx126x shield, and sx128x 2.4GHz. The ST board B-L072Z-LRWAN1 is also supported (TypeABZ module). When B-L072Z-LRWAN1
target is selected, TARGET_DISCO_L072CZ_LRWAN1
is defined by tools, allowing correct radio driver configuration for this platform. Alternately, any mbed board that can use LoRa radio shield board should work, but NUCLEO boards are tested.
End-node Unique ID
DevEUI is created from CPU serial number. AppEUI and AppKey are declared as software constants.
End-node Configuration
Data rate definition LORAMAC_DEFAULT_DATARATE
configured in LoRaMac-definitions.h
. See gateway project page for configuration of gateway.
LoRaWAN addressing is configured in Comissioning.h
; only OTA mode is functional.
Header file board/lora_config.h
, selects application layer options (i.e. sensors) to be compiled in.
Serial Interface
Serial port operates at 115200bps.
Application layer single_us915_main.cpp
User button triggers uplink (i.e. blue button on nucleo board), or jumper enables continuously sends repeated uplink packets. The MAC layer holds each uplink request until the allocated timeslot.
command | arguments | description |
---|---|---|
? | - | print available commands |
. (period) | - | print status (DevEUI, DevAddr, etc) |
ul | length integer | set payload length of test uplink packets |
sensor demo
Selected grove sensors may be plugged into SX1272 shield.
To enable, edit lora_config.h
to define SENSORS
.
Sensor connections on SX1272MB2xAS:
D8 D9: button | RX TX: (unused) | A3 A4: Rotary Angle Sensor |
D6 D7: RGB LED | SCL SDA: digital light sensor | A1 A2: Rotary Angle Sensor |
Digital input pin, state reported via uplink: PC8
Digital output pin, controlled via downlink: PC6
PWM out: PB_10
Jumper enables auto-repeated transmit: PC10
and PC12
on NUCLEO board, located on end of morpho headers nearby JP4.
Diff: mac/LoRaMac.cpp
- Revision:
- 29:ad409c68c0a6
- Parent:
- 25:fed9d5b77183
- Child:
- 30:1c35c4f56e50
--- a/mac/LoRaMac.cpp Mon Aug 28 13:13:56 2017 -0700 +++ b/mac/LoRaMac.cpp Fri Dec 07 17:57:41 2018 -0800 @@ -15,19 +15,26 @@ License: Revised BSD License, see LICENSE.TXT file include in the project -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE ) */ #include <math.h> #include "board.h" +#include "radio.h" #include "LoRaMacCrypto.h" #include "LoRaMac.h" #include "LoRaMacTest.h" - -#define TX_DEBUG +#include "LowPowerTimeoutAbs.h" + +//DigitalOut pc2(PC_2); +#define BEACONS_MISSED_LIMIT 16 #define PING_SLOT_RESOLUTION_us 30000 +#define PREAMBLE_SYMBS 8 + +#define TARGET_PRECESSION_us 3000 +#define BEACON_RX_TIMEOUT_LOCKED_us 8000 + /*! * Maximum PHY layer payload size */ @@ -38,29 +45,10 @@ */ #define LORA_MAC_COMMAND_MAX_LENGTH 15 -/*! - * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength - * in RxWindowSetup function. - * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD - */ -#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) - -/*! - * LoRaMac duty cycle for the back-off procedure during the first hour. - */ -#define BACKOFF_DC_1_HOUR 100 - -/*! - * LoRaMac duty cycle for the back-off procedure during the next 10 hours. - */ -#define BACKOFF_DC_10_HOURS 1000 - -/*! - * LoRaMac duty cycle for the back-off procedure during the next 24 hours. - */ -#define BACKOFF_DC_24_HOURS 10000 - -#define DIO0_LAG_us 1000 +/*! radio timer started later by this much: */ +static volatile int lpt_offset; + +static volatile us_timestamp_t txDoneAt; /*! * Device IEEE EUI @@ -117,34 +105,13 @@ static MulticastParams_t *MulticastChannels = NULL; /*! - * Actual device class - */ -static DeviceClass_t LoRaMacDeviceClass; - -/*! * Indicates if the node is connected to a private or public network */ static bool PublicNetwork; -/*! - * Buffer containing the data to be sent or received. - */ -static uint8_t LoRaMacBuffer[LORAMAC_PHY_MAXPAYLOAD]; - -/*! - * Length of packet in LoRaMacBuffer - */ -static uint16_t LoRaMacBufferPktLen = 0; - -/*! - * Length of the payload in LoRaMacBuffer - */ -static uint8_t LoRaMacTxPayloadLen = 0; - -/*! - * Buffer containing the upper layer data. - */ -static uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD]; +uint8_t tx_buf_len; + +static uint8_t rxFRMPayload[244]; /*! * LoRaMAC frame counter. Each time a packet is sent the counter is incremented. @@ -168,24 +135,8 @@ * Used for test purposes. Disables the opening of the reception windows. */ static bool IsRxWindowsEnabled = true; -LowPowerTimeout rx_timeout; - -/*! - * Indicates if the MAC layer has already joined a network. - */ -static bool IsLoRaMacNetworkJoined = false; - -/*! - * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates - * if the nodes needs to manage the server acknowledgement. - */ -static bool NodeAckRequested = false; - -/*! - * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates - * if the ACK bit must be set for the next transmission - */ -static bool SrvAckRequested = false; +LowPowerTimeoutAbs _rx_timeout; +volatile us_timestamp_t _rx_timeout_setAt; /*! * Indicates if the MAC layer wants to send MAC commands @@ -216,24 +167,46 @@ #define BEACON_CHANNEL_DR LORAMAC_DEFAULT_DATARATE -#if defined( USE_BAND_915_SINGLE ) +#ifdef SX128x_H + + #define LORA_MAX_NB_CHANNELS 8 + + // 0 1 2 3 4 5 6 7 + const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 6, 5 }; + #define SF_FROM_DR0 12 /* DR0 is sf12 */ + #define SF_FROM_DR1 11 /* DR1 is sf11 */ + #define SF_FROM_DR2 10 /* DR2 is sf10 */ + #define SF_FROM_DR3 9 /* DR3 is sf9 */ + #define SF_FROM_DR4 8 /* DR4 is sf8 */ + #define SF_FROM_DR5 7 /* DR5 is sf7 */ + #define SF_FROM_DR6 6 /* DR5 is sf6 */ + #define SF_FROM_DR7 5 /* DR7 is sf5 */ + + + const int8_t TxPowers[] = { 12, 5 }; + #define LORAMAC_FIRST_CHANNEL ( (uint32_t)2486.9e6 ) + #define LORAMAC_STEPWIDTH_CHANNEL ( (uint32_t)300e3 ) + + #define LORA_BANDWIDTH_KHZ 200 + +/* +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) +#pragma message "content of BEACON_RXDONE_LATENCY_us: " STR(BEACON_RXDONE_LATENCY_us) +*/ + + /* end sx1280 */ +#elif defined( USE_BAND_915_SINGLE ) /*! * Data rates table definition - */ + DR: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/ const uint8_t Datarates[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 }; - - /*! - * Bandwidths table definition in Hz - */ - const uint32_t Bandwidths[] = { 125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 }; - - /*! - * LoRaMac bands - */ - /*static Band_t Bands[LORA_MAX_NB_BANDS] = - { - BAND0, - };*/ + #define SF_FROM_DR8 12 + #define SF_FROM_DR9 11 + #define SF_FROM_DR10 10 + #define SF_FROM_DR11 9 + #define SF_FROM_DR12 8 + #define SF_FROM_DR13 7 /*! * Tx output powers table definition @@ -244,88 +217,109 @@ #define LORAMAC_STEPWIDTH_CHANNEL ( (uint32_t)800e3 ) #define LORA_MAX_NB_CHANNELS 8 - #define LORA_BANDWIDTH 2 /* 2=500KHz */ - - /* measured beacon duration (all at bw500, 6 byte fixed payload length) - * latency assigned for correct rx-before-tx measurement */ - #if (LORAMAC_DEFAULT_DATARATE == DR_8) - #define BEACON_RXDONE_LATENCY_us 6000 - #define BEACON_TOA_us 209000 - #elif (LORAMAC_DEFAULT_DATARATE == DR_9) - #define BEACON_RXDONE_LATENCY_us 3500 - #define BEACON_TOA_us 105000 - #elif (LORAMAC_DEFAULT_DATARATE == DR_10) - #define BEACON_RXDONE_LATENCY_us 1460 - #define BEACON_TOA_us 52800 - #elif (LORAMAC_DEFAULT_DATARATE == DR_11) - #define BEACON_RXDONE_LATENCY_us 2000 - #define BEACON_TOA_us 26000 - #elif (LORAMAC_DEFAULT_DATARATE == DR_12) - #define BEACON_RXDONE_LATENCY_us 1500 - #define BEACON_TOA_us 12800 - #elif (LORAMAC_DEFAULT_DATARATE == DR_13) - #define BEACON_RXDONE_LATENCY_us 1300 - #define BEACON_TOA_us 6560 - #else - #error datarate - #endif + #define LORA_BANDWIDTH_KHZ 500 +/* +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) +#pragma message "content of BEACON_RXDONE_LATENCY_us: " STR(BEACON_RXDONE_LATENCY_us) +#pragma message "content of BEACON_TOA_us: " STR(BEACON_TOA_us) +*/ /* end us915 */ -#elif defined(USE_BAND_433) && defined(ENABLE_SX1276) +#elif defined(USE_BAND_433) + // DR: 0 1 2 3 4 5 6 7 const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; - const uint32_t Bandwidths[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 }; + #define SF_FROM_DR0 12 + #define SF_FROM_DR1 11 + #define SF_FROM_DR2 10 + #define SF_FROM_DR3 9 + #define SF_FROM_DR4 8 + #define SF_FROM_DR5 7 + const int8_t TxPowers[] = { 10, 7, 4, 1, -2, -5 }; - #define LORA_BANDWIDTH 0 /* 0=125KHz */ + #define LORA_BANDWIDTH_KHZ 125 #define LORAMAC_FIRST_CHANNEL ( (uint32_t)433.32e6 ) #define LORAMAC_STEPWIDTH_CHANNEL ( (uint32_t)200e3 ) #define LORA_MAX_NB_CHANNELS 7 - #if (LORAMAC_DEFAULT_DATARATE == DR_0) - #define BEACON_RXDONE_LATENCY_us 27500 - #define BEACON_TOA_us 828100 - #elif (LORAMAC_DEFAULT_DATARATE == DR_1) - #define BEACON_RXDONE_LATENCY_us 12500 - #define BEACON_TOA_us 414400 - #elif (LORAMAC_DEFAULT_DATARATE == DR_2) - #define BEACON_RXDONE_LATENCY_us 6000 - #define BEACON_TOA_us 207500 - #elif (LORAMAC_DEFAULT_DATARATE == DR_3) - #define BEACON_RXDONE_LATENCY_us 3840 - #define BEACON_TOA_us 103000 - #elif (LORAMAC_DEFAULT_DATARATE == DR_4) - #define BEACON_RXDONE_LATENCY_us 2800 - #define BEACON_TOA_us 51000 - #elif (LORAMAC_DEFAULT_DATARATE == DR_5) - #define BEACON_RXDONE_LATENCY_us 1400 - #define BEACON_TOA_us 25800 - #else - #error datarate - #endif - /* end USE_BAND_433 */ #else #error "Please define a frequency band in the compiler options." #endif +#define _SF_FROM_DR(dr) SF_FROM_DR ## dr +#define SF_FROM_DR_(x) _SF_FROM_DR(x) + +#ifdef SX128x_H + + #define LATENCY_FROM_1600KHZ_SF12 17300 + #define LATENCY_FROM_1600KHZ_SF11 16900 + #define LATENCY_FROM_1600KHZ_SF10 4300 + #define LATENCY_FROM_1600KHZ_SF9 4000 + #define LATENCY_FROM_1600KHZ_SF8 1050 + #define LATENCY_FROM_1600KHZ_SF7 1000 + #define LATENCY_FROM_1600KHZ_SF6 504 + #define LATENCY_FROM_1600KHZ_SF5 256 + + #define _LATENCY_FROM_SF(sf) LATENCY_FROM_1600KHZ_SF ## sf + #define LATENCY_FROM_SF_(x) _LATENCY_FROM_SF(x) + + /* 6 byte implict packet */ + #define BEACON_TOA_FROM_1600KHZ_SF12 66000 + #define BEACON_TOA_FROM_1600KHZ_SF11 33100 + #define BEACON_TOA_FROM_1600KHZ_SF10 16400 + #define BEACON_TOA_FROM_1600KHZ_SF9 8260 + #define BEACON_TOA_FROM_1600KHZ_SF8 5100 + #define BEACON_TOA_FROM_1600KHZ_SF7 2560 + #define BEACON_TOA_FROM_1600KHZ_SF6 1350 + #define BEACON_TOA_FROM_1600KHZ_SF5 800 + + #define BEACON_RXDONE_LATENCY_us (LATENCY_FROM_SF_( SF_FROM_DR_(LORAMAC_DEFAULT_DATARATE) ) * (1600/LORA_BANDWIDTH_KHZ)) + + #define _BEACON_TOA_FROM_SF(sf) BEACON_TOA_FROM_1600KHZ_SF ## sf + #define BEACON_TOA_FROM_SF_(x) _BEACON_TOA_FROM_SF(x) + #define BEACON_TOA_us (BEACON_TOA_FROM_SF_( SF_FROM_DR_(LORAMAC_DEFAULT_DATARATE) ) * (1600/LORA_BANDWIDTH_KHZ)) + +#elif defined(SX126x_H) || defined(SX127x_H) + + /* 6 byte implict packet */ + #define BEACON_TOA_FROM_500KHZ_SF12 198000 + #define BEACON_TOA_FROM_500KHZ_SF11 97750 + #define BEACON_TOA_FROM_500KHZ_SF10 49630 + #define BEACON_TOA_FROM_500KHZ_SF9 24500 + #define BEACON_TOA_FROM_500KHZ_SF8 12500 + #define BEACON_TOA_FROM_500KHZ_SF7 6250 + #define BEACON_TOA_FROM_500KHZ_SF6 3320 + #define BEACON_TOA_FROM_500KHZ_SF5 1940 + + #define LATENCY_FROM_500KHZ_SF12 7750 + #define LATENCY_FROM_500KHZ_SF11 3600 + #define LATENCY_FROM_500KHZ_SF10 1675 + #define LATENCY_FROM_500KHZ_SF9 7875 + #define LATENCY_FROM_500KHZ_SF8 385 + #define LATENCY_FROM_500KHZ_SF7 195 + #define LATENCY_FROM_500KHZ_SF6 103 + #define LATENCY_FROM_500KHZ_SF5 48 + + #define _LATENCY_FROM_SF(sf) LATENCY_FROM_500KHZ_SF ## sf + #define LATENCY_FROM_SF_(x) _LATENCY_FROM_SF(x) + + #define BEACON_RXDONE_LATENCY_us (LATENCY_FROM_SF_( SF_FROM_DR_(LORAMAC_DEFAULT_DATARATE) ) * (500/LORA_BANDWIDTH_KHZ)) + + #define _BEACON_TOA_FROM_SF(sf) BEACON_TOA_FROM_500KHZ_SF ## sf + #define BEACON_TOA_FROM_SF_(x) _BEACON_TOA_FROM_SF(x) + #define BEACON_TOA_us (BEACON_TOA_FROM_SF_( SF_FROM_DR_(LORAMAC_DEFAULT_DATARATE) ) * (500/LORA_BANDWIDTH_KHZ)) +#endif /* SX126x_H || SX127x_H */ + +const us_timestamp_t beaconDuration = BEACON_TOA_us + BEACON_RXDONE_LATENCY_us; + static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS]; // populated in init #define BEACON_GUARD_us 2000000 // pre-beacon start #define BEACON_RESERVED_us 2120000 // post-beacon start -#define BEACON_MIN_SYMBOL_TIMEOUT 8 - -LowPowerTimer lp_timer; - -#ifdef DEBUG_GWTX_JUMPER -InterruptIn gwtx_pin(DEBUG_GWTX_JUMPER); -unsigned int gwtx_rise_us; - -void gwtx_pin_callback() -{ - gwtx_rise_us = lp_timer.read_us(); -} -#endif +#define MIN_SYMBOL_TIMEOUT 8 // number of symbols to keep receiver open for /*! * LoRaMac parameters @@ -342,21 +336,12 @@ */ static uint8_t ChannelsNbRepCounter = 0; -static uint32_t AggregatedLastTxDoneTime_us; - /*! * Current channel index */ static uint8_t Channel; /*! - * Stores the time at LoRaMac initialization. - * - * \remark Used for the BACKOFF_DC computation. - */ -//static TimerTime_t LoRaMacInitializationTime = 0; - -/*! * LoRaMac upper layer event functions */ static LoRaMacPrimitives_t *LoRaMacPrimitives; @@ -367,15 +352,9 @@ static LoRaMacCallback_t *LoRaMacCallbacks; /*! - * Radio events function pointer - */ -static RadioEvents_t RadioEvents; - -/*! * LoRaMac duty cycle delayed Tx timer */ -LowPowerTimeout tx_timeout; - +LowPowerTimeoutAbs _tx_timeout; /*! * LoRaMac reception windows delay @@ -393,29 +372,30 @@ static struct beacon_struct { int rx_precession_us; // positive: rxing before tx start, negative: rxing after tx start - unsigned int RxBeaconSetupAt_us; - unsigned int LastBeaconRx_us; // updated only at beacon reception + us_timestamp_t rx_setup_at; + us_timestamp_t LastBeaconRx_us; // updated only at beacon reception + us_timestamp_t sendAt; + int lastSendAtErr; int last_BeaconRxTimerError_us; int known_working_BeaconRxTimerError_us; - float symbol_period_secs; + unsigned symbol_period_us; uint8_t Precess_symbols; // how many symbols we want to start receiver before expected transmitter - uint16_t SymbolTimeout; - float SymbolTimeout_sec; + uint16_t nSymbsTimeout; + unsigned SymbolTimeout_us; uint8_t num_missed; beacon_state_e state; uint16_t tx_slot_offset; uint16_t periodicity_slots; - - LowPowerTimeout timeout_rx; - LowPowerTimeout timeout_guard; + uint16_t sendOpportunities; + + LowPowerTimeoutAbs _timeout_rx; + LowPowerTimeoutAbs _timeout_guard; bool guard; - unsigned guard_at; } BeaconCtx; -bool expecting_beacon; /*! * Rx window parameters @@ -423,24 +403,19 @@ typedef struct { int8_t Datarate; - uint8_t Bandwidth; uint32_t RxWindowTimeout; - int32_t RxOffset; -}RxConfigParams_t; +} RxConfigParams_t; /*! * Rx windows params */ static RxConfigParams_t RxWindowsParam; - /*! * Acknowledge timeout timer. Used for packet retransmissions. */ static LowPowerTimeout AckTimeoutTimer; -uint32_t TxTimeOnAir = 0; - /*! * Number of trials for the Join Request */ @@ -474,19 +449,7 @@ /*! * LoRaMac tx/rx operation state */ -LoRaMacFlags_t LoRaMacFlags; -static volatile struct { - uint8_t rx_win : 1; - uint8_t join_send : 1; - uint8_t beacon_setup : 1; - uint8_t send : 1; -} flags; - -/*! - * \brief Function to be executed on Radio Tx Done event - */ -static void OnRadioTxDone( unsigned int tx_done_us ); -unsigned int TxDone_us; +volatile LoRaMacFlags_t LoRaMacFlags; /*! * \brief This function prepares the MAC to abort the execution of function @@ -495,11 +458,6 @@ static void PrepareRxDoneAbort( void ); /*! - * \brief Function to be executed on Radio Rx Done event - */ -static void OnRadioRxDone(unsigned rx_us, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); - -/*! * \brief Function executed on Radio Tx Timeout event */ static void OnRadioTxTimeout( void ); @@ -514,26 +472,11 @@ */ static void OnRadioRxTimeout( void ); -static void OnRxWindowTimerEvent( void ); - /*! * \brief Function executed on AckTimeout timer event */ static void OnAckTimeoutTimerEvent( void ); - -/*! - * \brief Initializes and opens the reception window - * - * \param [IN] freq window channel frequency - * \param [IN] datarate window channel datarate - * \param [IN] bandwidth window channel bandwidth - * \param [IN] timeout window channel timeout - * - * \retval status Operation status [true: Success, false: Fail] - */ -static bool RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous ); - /*! * \brief Adds a new MAC command to be sent. * @@ -632,6 +575,60 @@ */ LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power ); +#ifdef SX127x_H +void printLoraIrqs(bool clear) +{ + pc.printf("\r\nIrqFlags:"); + if (Radio::lora.RegIrqFlags.bits.CadDetected) + pc.printf("CadDetected "); + if (Radio::lora.RegIrqFlags.bits.FhssChangeChannel) { + pc.printf("FhssChangeChannel:%d ", Radio::lora.RegHopChannel.bits.FhssPresentChannel); + } + if (Radio::lora.RegIrqFlags.bits.CadDone) + pc.printf("CadDone "); + if (Radio::lora.RegIrqFlags.bits.TxDone) + pc.printf("TxDone-dio0:%d ", Radio::radio.dio0.read()); + if (Radio::lora.RegIrqFlags.bits.ValidHeader) + pc.printf("[42mValidHeader[0m "); + if (Radio::lora.RegIrqFlags.bits.PayloadCrcError) + pc.printf("[41mPayloadCrcError[0m "); + if (Radio::lora.RegIrqFlags.bits.RxDone) + pc.printf("[42mRxDone[0m "); + if (Radio::lora.RegIrqFlags.bits.RxTimeout) + pc.printf("RxTimeout "); + + pc.printf("\r\n"); + + if (clear) + Radio::radio.write_reg(REG_LR_IRQFLAGS, Radio::lora.RegIrqFlags.octet); +} + +void printOpMode() +{ + Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE); + switch (Radio::radio.RegOpMode.bits.Mode) { + case RF_OPMODE_SLEEP: pc.printf("[7msleep[0m"); break; + case RF_OPMODE_STANDBY: pc.printf("[7mstby[0m"); break; + case RF_OPMODE_SYNTHESIZER_TX: pc.printf("[33mfstx[0m"); break; + case RF_OPMODE_TRANSMITTER: pc.printf("[31mtx[0m"); break; + case RF_OPMODE_SYNTHESIZER_RX: pc.printf("[33mfsrx[0m"); break; + case RF_OPMODE_RECEIVER: pc.printf("[32mrx[0m"); break; + case 6: + if (Radio::radio.RegOpMode.bits.LongRangeMode) + pc.printf("[42mrxs[0m"); + else + pc.printf("-6-"); + break; // todo: different lora/fsk + case 7: + if (Radio::radio.RegOpMode.bits.LongRangeMode) + pc.printf("[45mcad[0m"); + else + pc.printf("-7-"); + break; // todo: different lora/fsk + } +} +#endif /* SX127x_H */ + /*! * \brief Resets MAC specific parameters to default */ @@ -640,70 +637,143 @@ void loramac_print_status() { - isr_printf("DR%u=sf%u guard:%d\r\n", + int until_beacon = BeaconCtx.rx_setup_at - BeaconCtx._timeout_rx.read_us(); + mac_printf("until_beacon:%d ", until_beacon); + mac_printf("DR%u=sf%u guard:%d\r\n", LoRaMacParams.ChannelsDatarate_fixed, Datarates[LoRaMacParams.ChannelsDatarate_fixed], BeaconCtx.guard ); +#ifdef SX128x_H + status_t status; + Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet); + switch (status.bits.cmdStatus) { + case 1: pc.printf("success"); break; + case 2: pc.printf("dataAvail"); break; + case 3: pc.printf("cmdTimeout"); break; + case 4: pc.printf("cmdErr"); break; + case 5: pc.printf("exeFail"); break; + case 6: pc.printf("txdone"); break; + default: pc.printf("cmdStatus:<%u>", status.bits.cmdStatus); break; + } + pc.printf(" "); + switch (status.bits.chipMode) { + case 2: pc.printf("stdby_rc"); break; + case 3: pc.printf("stdby_xosc"); break; + case 4: pc.printf("fs"); break; + case 5: pc.printf("\e[32mrx\e[0m"); break; + case 6: pc.printf("\e[31mtx\e[0m"); break; + default: pc.printf("chipMode:<%u>", status.bits.chipMode); break; + } + LoRaPktPar0_t LoRaPktPar0; + LoRaPktPar0.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR0, 1); + pc.printf(" bw:%u sf%u ", LoRaPktPar0.bits.modem_bw, LoRaPktPar0.bits.modem_sf); + mac_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2)); +#elif defined(SX127x_H) + Radio::radio.RegPaConfig.octet = Radio::radio.read_reg(REG_PACONFIG); + if (Radio::radio.RegPaConfig.bits.PaSelect) + pc.printf("PA_BOOST "); + else + pc.printf("RFO "); + + Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE); + pc.printf("%.3fMHz sf%ubw%u ", Radio::radio.get_frf_MHz(), Radio::lora.getSf(), Radio::lora.getBw()); + pc.printf("dio0pin:%u ", Radio::radio.dio0.read()); + printOpMode(); + if (!Radio::radio.RegOpMode.bits.LongRangeMode) { + pc.printf("FSK\r\n"); + return; + } + + Radio::lora.RegIrqFlags.octet = Radio::radio.read_reg(REG_LR_IRQFLAGS); + printLoraIrqs(false); + + Radio::lora.RegTest33.octet = Radio::radio.read_reg(REG_LR_TEST33); // invert_i_q + Radio::lora.RegDriftInvert.octet = Radio::radio.read_reg(REG_LR_DRIFT_INVERT); + pc.printf("modemstat:%02x, rxinv:%x,%x\r\n", Radio::radio.read_reg(REG_LR_MODEMSTAT), Radio::lora.RegTest33.octet, Radio::lora.RegDriftInvert.octet); + Radio::radio.RegDioMapping1.octet = Radio::radio.read_reg(REG_DIOMAPPING1); + pc.printf("\r\ndio0map:%u\r\n", Radio::radio.RegDioMapping1.bits.Dio0Mapping); + pc.printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", Radio::radio.read_reg(REG_LR_FIFOADDRPTR), Radio::radio.read_reg(REG_LR_FIFORXBASEADDR)); +#elif defined(SX126x_H) + status_t status; + Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet); + switch (status.bits.chipMode) { + case 2: mac_printf("STBY_RC"); break; + case 3: mac_printf("STBY_XOSC"); break; + case 4: mac_printf("FS"); break; + case 5: mac_printf("RX"); break; + case 6: mac_printf("TX"); break; + default: mac_printf("%u", status.bits.chipMode); break; + } + pc.printf(" "); + switch (status.bits.cmdStatus) { + case 1: mac_printf("rfu"); break; + case 2: mac_printf("dataAvail"); break; + case 3: mac_printf("timeout"); break; + case 4: mac_printf("err"); break; + case 5: mac_printf("fail"); break; + case 6: mac_printf("txdone"); break; + default: mac_printf("%u", status.bits.cmdStatus); break; + } + loraConfig0_t conf0; + conf0.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG0, 1); + // bw7=125 bw8=250 b9=500 + mac_printf(" bw:%u sf%u\r\n", conf0.bits.modem_bw, conf0.bits.modem_sf); + loraConfig1_t conf1; + conf1.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG1, 1); + mac_printf("inviq:%u cr%u\r\n", conf1.bits.rx_invert_iq, conf1.bits.tx_coding_rate); + mac_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2)); +#endif /* ..SX126x_H */ } -/* - * Rx window precise timing - * - * For more details please consult the following document, chapter 3.1.2. - * http://www.semtech.com/images/datasheet/SX1272_settings_for_LoRaWAN_v2.0.pdf - * or - * http://www.semtech.com/images/datasheet/SX1276_settings_for_LoRaWAN_v2.0.pdf - * - * Downlink start: T = Tx + 1s (+/- 20 us) - * | - * TRxEarly | TRxLate - * | | | - * | | +---+---+---+---+---+---+---+---+ - * | | | Latest Rx window | - * | | +---+---+---+---+---+---+---+---+ - * | | | - * +---+---+---+---+---+---+---+---+ - * | Earliest Rx window | - * +---+---+---+---+---+---+---+---+ - * | - * +---+---+---+---+---+---+---+---+ - *Downlink preamble 8 symbols | | | | | | | | | - * +---+---+---+---+---+---+---+---+ - * - * Worst case Rx window timings - * - * TRxLate = DEFAULT_MIN_RX_SYMBOLS * tSymbol - RADIO_WAKEUP_TIME - * TRxEarly = 8 - DEFAULT_MIN_RX_SYMBOLS * tSymbol - RxWindowTimeout - RADIO_WAKEUP_TIME - * - * TRxLate - TRxEarly = 2 * DEFAULT_SYSTEM_MAX_RX_ERROR - * - * RxOffset = ( TRxLate + TRxEarly ) / 2 - * - * RxWindowTimeout = ( 2 * DEFAULT_MIN_RX_SYMBOLS - 8 ) * tSymbol + 2 * DEFAULT_SYSTEM_MAX_RX_ERROR - * RxOffset = 4 * tSymbol - RxWindowTimeout / 2 - RADIO_WAKE_UP_TIME - * - * Minimal value of RxWindowTimeout must be 5 symbols which implies that the system always tolerates at least an error of 1.5 * tSymbol - */ -/*! - * Computes the Rx window parameters. - * - * \param [IN] datarate Rx window datarate to be used - * \param [IN] rxError Maximum timing error of the receiver. in milliseconds - * The receiver will turn on in a [-rxError : +rxError] ms - * interval around RxOffset - * - * \retval rxConfigParams Returns a RxConfigParams_t structure. - */ +static void RxWindowSetup( uint32_t freq, int8_t datarate, uint16_t timeout, bool rxContinuous ) +{ + uint8_t downlinkDatarate = Datarates[datarate]; + + Radio::SetChannel( freq ); + + // Store downlink datarate + McpsIndication.RxDatarate = ( uint8_t ) datarate; + + Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, downlinkDatarate, 1); + + // preambleLen, fixLen, crcOn, invIQ + Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, false, true); + Radio::SetLoRaSymbolTimeout(timeout); + Radio::SetRxMaxPayloadLength(LORAMAC_PHY_MAXPAYLOAD); + +} // ..RxWindowSetup() + +static void OnRxWindowTimerEvent( void ) +{ + RxWindowSetup(Channels[Channel].Frequency, RxWindowsParam.Datarate, RxWindowsParam.RxWindowTimeout, false); + Radio::Rx( LoRaMacParams.MaxRxWindow ); + //mac_printf("rxwinTo:%u\r\n", RxWindowsParam.RxWindowTimeout); +#ifdef SX128x_H + { + LoRaPktPar1_t LoRaPktPar1; + LoRaPktPar1.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR1, 1); + mac_printf("dnRxiq:"); + if (LoRaPktPar1.bits.rxinvert_iq) { + mac_printf("IQ_STD\r\n"); + } else { + mac_printf("IQ_INV\r\n"); + } + } +#endif /* SX128x_H */ +} + static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError ); -static void OnRadioTxDone( unsigned int tx_done_us ) +static void OnRadioTxDone_bh() { // Setup timers if (IsRxWindowsEnabled) { - rx_timeout.attach_us(&OnRxWindowTimerEvent, RxWindowDelay_us); - if (NodeAckRequested) + int delay = lpt_offset + RxWindowDelay_us; + _rx_timeout_setAt = Radio::irqAt + delay; + _rx_timeout.attach_us(&OnRxWindowTimerEvent, _rx_timeout_setAt); + if (LoRaMacFlags.Bits.NodeAckRequested) { AckTimeoutTimer.attach_us(&OnAckTimeoutTimerEvent, (RxWindowDelay_us/1000) + ACK_TIMEOUT_us + randr(-ACK_TIMEOUT_RND_us, ACK_TIMEOUT_RND_us)); } @@ -719,22 +789,20 @@ } LoRaMacFlags.Bits.MacDone = 1; } - Radio.Sleep( ); - TxDone_us = tx_done_us; - - // Update Aggregated last tx done time - AggregatedLastTxDoneTime_us = tx_done_us; - // Update Backoff - - if (!NodeAckRequested) + + if (!LoRaMacFlags.Bits.NodeAckRequested) { McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; ChannelsNbRepCounter++; } - + MlmeIndication.MlmeIndication = MLME_TXDONE; MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; - LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication ); + LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication ); + + Radio::Standby( ); + + txDoneAt = Radio::irqAt + lpt_offset; } @@ -744,192 +812,134 @@ LoRaMacFlags.Bits.McpsInd = 0; LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); } - + if (LoRaMacFlags.Bits.McpsReq) { LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm ); LoRaMacFlags.Bits.McpsReq = 0; - } + } } static void PrepareRxDoneAbort( void ) { - if (NodeAckRequested) + if (LoRaMacFlags.Bits.NodeAckRequested) { OnAckTimeoutTimerEvent( ); } LoRaMacFlags.Bits.McpsInd = 1; LoRaMacFlags.Bits.MacDone = 1; - + application_callbacks(); } void send_bh() -{ - int8_t datarate = Datarates[LoRaMacParams.ChannelsDatarate_fixed]; - int8_t txPowerIndex = 0; - int8_t txPower = 0; - - txPowerIndex = LoRaMacParams.ChannelsTxPower; - txPower = TxPowers[txPowerIndex]; - +{ MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_SEND; McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_SEND; - McpsConfirm.TxPower = txPowerIndex; + McpsConfirm.TxPower = LoRaMacParams.ChannelsTxPower; McpsConfirm.UpLinkFrequency = Channels[Channel].Frequency; - if (!IsLoRaMacNetworkJoined) // joining is channel hunting - Radio.SetChannel( Channels[Channel].Frequency ); - -#if defined( USE_BAND_915_SINGLE ) - // High speed LoRa channel BW500 kHz - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); -#elif defined(USE_BAND_433) && defined (ENABLE_SX1276) - if( LoRaMacParams.ChannelsDatarate_fixed == DR_7 ) - { // High Speed FSK channel - //Radio.SetMaxPayloadLength( MODEM_FSK, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, 0, 0, false, 3e3 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen ); - - } - else if( LoRaMacParams.ChannelsDatarate_fixed == DR_6 ) - { // High speed LoRa channel - //Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); - } - else - { // Normal LoRa channel - //Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); - } -#endif - - // Store the time on air - McpsConfirm.TxTimeOnAir = TxTimeOnAir; - MlmeConfirm.TxTimeOnAir = TxTimeOnAir; - - if (!IsLoRaMacNetworkJoined) + if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) // joining is channel hunting + Radio::SetChannel( Channels[Channel].Frequency ); + + if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) { JoinRequestTrials++; - isr_printf("join %luhz try%u DR%u\r\n", Channels[Channel].Frequency, JoinRequestTrials, LoRaMacParams.ChannelsDatarate_fixed); + mac_printf("join %luhz try%u DR%u\r\n", Channels[Channel].Frequency, JoinRequestTrials, LoRaMacParams.ChannelsDatarate_fixed); } - Radio.SetTxConfig( - /* RadioModems_t modem */ MODEM_LORA, - /* int8_t power */ TxPowers[LoRaMacParams.ChannelsTxPower], - /* uint32_t fdev */ 0, - /* uint32_t bandwidth */ LORA_BANDWIDTH, - /* uint32_t datarate */ Datarates[LoRaMacParams.ChannelsDatarate_fixed], - /* uint8_t coderate */ 1, - /* uint16_t preambleLen */ 8, - /* bool fixLen */ false, - /* bool crcOn */ true, - /* bool freqHopOn */ 0, - /* uint8_t hopPeriod */ 0, - /* bool iqInverted */ false, - /* uint32_t timeout */ 3e3 - ); - Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen ); - + Radio::set_tx_dbm(TxPowers[LoRaMacParams.ChannelsTxPower]); + Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, Datarates[LoRaMacParams.ChannelsDatarate_fixed], 1); + + // preambleLen, fixLen, crcOn, invIQ + Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false); + Radio::Send(tx_buf_len, 0, 0, 0); + LoRaMacFlags.Bits.uplink_pending = 0; // sent // Compute Rx1 windows parameters, taken at TxDone - if (!IsLoRaMacNetworkJoined) - RxWindowDelay_us = LoRaMacParams.JoinAcceptDelay_us + RxWindowsParam.RxOffset; + if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) + RxWindowDelay_us = LoRaMacParams.JoinAcceptDelay_us - TARGET_PRECESSION_us; else - RxWindowDelay_us = LoRaMacParams.ReceiveDelay_us + RxWindowsParam.RxOffset; - - RxWindowDelay_us -= DIO0_LAG_us; -} + RxWindowDelay_us = LoRaMacParams.ReceiveDelay_us - TARGET_PRECESSION_us; + +} // ..send_bh() void send_callback() -{ +{ + int err = 0; + us_timestamp_t now = BeaconCtx.sendAt + BeaconCtx.lastSendAtErr; + if (BeaconCtx.guard) { /* last send, this will be restarted after beacon sent */ return; } - - tx_timeout.attach_us(&send_callback, BeaconCtx.periodicity_slots * 30000); - + BeaconCtx.sendOpportunities++; + + BeaconCtx.sendAt += BeaconCtx.periodicity_slots * PING_SLOT_RESOLUTION_us; + if (BeaconCtx.state == BEACON_STATE_LOCKED) { + float sinceBeacon = now - BeaconCtx.LastBeaconRx_us; + float ratio = sinceBeacon / BEACON_INTERVAL_us; + err = BeaconCtx.last_BeaconRxTimerError_us * ratio; + } + _tx_timeout.attach_us(&send_callback, BeaconCtx.sendAt + err); + BeaconCtx.lastSendAtErr = err; + if (LoRaMacFlags.Bits.uplink_pending) - flags.send = 1; + LoRaMacFlags.Bits.send = 1; } void OnRxBeaconSetup() { - flags.beacon_setup = 1; -} - -void OnRxBeaconSetupBH() -{ - unsigned int prevRxBeaconSetupAt_us; - unsigned now_us = lp_timer.read_us(); - - prevRxBeaconSetupAt_us = BeaconCtx.RxBeaconSetupAt_us; - BeaconCtx.RxBeaconSetupAt_us = now_us; - expecting_beacon = true; - - Radio.SetRxConfig( - /* RadioModems_t */ MODEM_LORA, - /* uint32_t bandwidth */ LORA_BANDWIDTH, - /* uint32_t datarate */ Datarates[BEACON_CHANNEL_DR], - /* uint8_t coderate */ 1, - /* uint32_t bandwidthAfc */ 0, - /* uint16_t preambleLen */ 10, - /* uint16_t symbTimeout */ BeaconCtx.SymbolTimeout, - /* bool fixLen */ true, - /* uint8_t payloadLen */ BEACON_SIZE, - /* bool crcOn */ false, - /* bool freqHopOn */ 0, - /* uint8_t hopPeriod */ 0, - /* bool iqInverted */ false, - /* bool rxContinuous */false - ); - - Radio.Rx(2000); - - unsigned int us_since_last_beacon_start = BeaconCtx.RxBeaconSetupAt_us - prevRxBeaconSetupAt_us; - isr_printf("OnRxBeaconSetup() %u since-last:%u\r\n", BeaconCtx.SymbolTimeout, us_since_last_beacon_start); + Radio::Standby( ); + + LoRaMacFlags.Bits.expecting_beacon = true; + + Radio::LoRaModemConfig(LORA_BANDWIDTH_KHZ, Datarates[BEACON_CHANNEL_DR], 1); + + // preambleLen, fixLen, crcOn, invIQ + Radio::LoRaPacketConfig(PREAMBLE_SYMBS, true, false, false); + Radio::SetFixedPayloadLength(BEACON_SIZE); + Radio::SetLoRaSymbolTimeout(BeaconCtx.nSymbsTimeout); + + Radio::Rx(2000); + + BeaconCtx.lastSendAtErr = 0; + +#ifdef SX128x_H + { + LoRaPktPar1_t LoRaPktPar1; + LoRaPktPar1.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR1, 1); + mac_printf("beaconRxiq:"); + if (LoRaPktPar1.bits.rxinvert_iq) { + mac_printf("IQ_STD\r\n"); + } else { + mac_printf("IQ_INV\r\n"); + } + } +#endif /* SX128x_H */ } void guard_callback() { - unsigned now_us = lp_timer.read_us(); - unsigned since_last = now_us - BeaconCtx.guard_at; - - if (BeaconCtx.state != BEACON_STATE_FIRST_ACQ && since_last < (BEACON_INTERVAL_us - 1000000)) { - isr_printf("guard-fail %u\r\n", since_last); - BeaconCtx.timeout_rx.detach(); - BeaconCtx.state = BEACON_STATE_NONE; - IsLoRaMacNetworkJoined = false; - - /*McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_STOP; - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_STOP; - LoRaMacFlags.Bits.MacDone = 1; - LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm );*/ - return; - } - - /* occurs BEACON_GUARD_us prior to OnRxBeaconSetup() */ BeaconCtx.guard = true; - isr_printf("guard since-last:%u\r\n", since_last); - - BeaconCtx.guard_at = now_us; + _tx_timeout.detach(); + mac_printf("sendOpportunities:%u\r\n", BeaconCtx.sendOpportunities); + BeaconCtx.sendOpportunities = 0; } -static void set_beacon_symbol_timeout(float secs) +static void us_to_nSymbTimeout(unsigned us) { - isr_printf("symTo:%.1f ", secs); - BeaconCtx.SymbolTimeout = secs / BeaconCtx.symbol_period_secs; - if (BeaconCtx.SymbolTimeout < (BEACON_MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols)) { - BeaconCtx.SymbolTimeout = BEACON_MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols; - } - BeaconCtx.SymbolTimeout_sec = BeaconCtx.SymbolTimeout * BeaconCtx.symbol_period_secs; - isr_printf("%u\r\n", BeaconCtx.SymbolTimeout); + mac_printf("symTo:%u ", us); + BeaconCtx.nSymbsTimeout = us / BeaconCtx.symbol_period_us; + if (BeaconCtx.nSymbsTimeout < (MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols)) { + BeaconCtx.nSymbsTimeout = MIN_SYMBOL_TIMEOUT+BeaconCtx.Precess_symbols; + } else if (BeaconCtx.nSymbsTimeout > 255) + BeaconCtx.nSymbsTimeout = 255; + + BeaconCtx.SymbolTimeout_us = BeaconCtx.nSymbsTimeout * BeaconCtx.symbol_period_us; + mac_printf("%u\r\n", BeaconCtx.nSymbsTimeout); } static uint16_t beacon_crc( uint8_t *buffer, uint16_t length ) @@ -956,78 +966,73 @@ return crc; } -/* low power timer needs larger value due to poor resolution */ -#define TARGET_PRECESSION_US 3000 -#define BEACON_RX_TIMEOUT_LOCKED 0.008 - -void rx_beacon(unsigned int rx_us, uint8_t* payload, uint16_t size) +void rx_beacon(uint16_t size) { static bool compensate_precession = false; int32_t compensation = 0; - unsigned ThisBeaconRx_us = rx_us - (BEACON_TOA_us + BEACON_RXDONE_LATENCY_us); - + us_timestamp_t ThisBeaconRx_us = Radio::irqAt + lpt_offset - beaconDuration; + + mac_printf("rx_beacon %llu ", Radio::irqAt); BeaconCtx.guard = false; - BeaconCtx.rx_precession_us = ThisBeaconRx_us - BeaconCtx.RxBeaconSetupAt_us; + BeaconCtx.rx_precession_us = ThisBeaconRx_us - BeaconCtx.rx_setup_at; if (BeaconCtx.state != BEACON_STATE_FIRST_ACQ) { - unsigned int us_since_last = ThisBeaconRx_us - BeaconCtx.LastBeaconRx_us; - unsigned int intervals_since_last = us_since_last / BEACON_INTERVAL_us; BeaconCtx.known_working_BeaconRxTimerError_us = BeaconCtx.last_BeaconRxTimerError_us; - /* get average of error history */ - BeaconCtx.last_BeaconRxTimerError_us = (ThisBeaconRx_us - BeaconCtx.LastBeaconRx_us) % BEACON_INTERVAL_us; - /* BeaconRxTimerError: positive means our clock is fast - * negative means our clock is slow */ - if (BeaconCtx.last_BeaconRxTimerError_us > (BEACON_INTERVAL_us/2)) - BeaconCtx.last_BeaconRxTimerError_us -= BEACON_INTERVAL_us; // negative value representing slow crystal - - if (intervals_since_last > 1) { - /* timer error is measured over more than one beacon period */ - BeaconCtx.last_BeaconRxTimerError_us /= intervals_since_last; + BeaconCtx.last_BeaconRxTimerError_us = (ThisBeaconRx_us - BeaconCtx.LastBeaconRx_us) - (BEACON_INTERVAL_us * (BeaconCtx.num_missed+1)); + + if (BeaconCtx.num_missed > 0) { + /* Timer error is measured over more than one beacon period. + * Scale to error seen over single beacon period */ + BeaconCtx.last_BeaconRxTimerError_us /= BeaconCtx.num_missed + 1; } if (BeaconCtx.state == BEACON_STATE_ACQ_ERROR) { - isr_printf("-->LOCKED "); + mac_printf("-->LOCKED "); BeaconCtx.state = BEACON_STATE_LOCKED; compensate_precession = true; - set_beacon_symbol_timeout(BEACON_RX_TIMEOUT_LOCKED); + us_to_nSymbTimeout(BEACON_RX_TIMEOUT_LOCKED_us); } } else { /* ignore precession at first acquisition because it has slot resolution added */ - isr_printf("-->ACQ_ERROR "); + mac_printf("-->ACQ_ERROR "); // next beacon will give us our crystal error BeaconCtx.state = BEACON_STATE_ACQ_ERROR; } -#ifdef DEBUG_GWTX_JUMPER - isr_printf("rx-before-gwtx:%d ", gwtx_rise_us - BeaconCtx.RxBeaconSetupAt_us); -#endif /* DEBUG_GWTX_JUMPER */ - isr_printf("err%d=%u-%u ", BeaconCtx.last_BeaconRxTimerError_us, ThisBeaconRx_us, BeaconCtx.LastBeaconRx_us); - isr_printf(" rx-before-tx:%d ", BeaconCtx.rx_precession_us); + mac_printf("err%d=%llu-%llu ", BeaconCtx.last_BeaconRxTimerError_us, ThisBeaconRx_us, BeaconCtx.LastBeaconRx_us); + if (BeaconCtx.num_missed > 0) + mac_printf("missed%u ", BeaconCtx.num_missed); + + mac_printf(" rx-before-tx:%d ", BeaconCtx.rx_precession_us); + if (BeaconCtx.last_BeaconRxTimerError_us > 40000 || BeaconCtx.last_BeaconRxTimerError_us < -40000) { + BeaconCtx._timeout_rx.detach(); + BeaconCtx._timeout_guard.detach(); + mac_printf("halt\r\n"); + for (;;) asm("nop"); + } BeaconCtx.LastBeaconRx_us = ThisBeaconRx_us; if (BeaconCtx.state == BEACON_STATE_LOCKED) { if (compensate_precession) { - compensation = BeaconCtx.rx_precession_us - TARGET_PRECESSION_US + BeaconCtx.last_BeaconRxTimerError_us; - isr_printf(" comp%ld", compensation); + compensation = BeaconCtx.rx_precession_us - TARGET_PRECESSION_us + BeaconCtx.last_BeaconRxTimerError_us; + mac_printf(" comp%ld", compensation); } } - unsigned int next_beacon_expected_us = BEACON_INTERVAL_us + compensation; - unsigned now_us = lp_timer.read_us(); - unsigned us_since_rx_setup = now_us - BeaconCtx.RxBeaconSetupAt_us; - unsigned timeout_us = next_beacon_expected_us - us_since_rx_setup; - BeaconCtx.timeout_rx.attach_us(&OnRxBeaconSetup, timeout_us); - BeaconCtx.timeout_guard.attach_us(&guard_callback, timeout_us - BEACON_GUARD_us); - - /***************************************/ - unsigned us_since_beacon_start = now_us - ThisBeaconRx_us; - timeout_us = BEACON_RESERVED_us + (BeaconCtx.tx_slot_offset * 30000) - us_since_beacon_start; - tx_timeout.attach_us(&send_callback, timeout_us); - /***************************************/ - isr_printf(" nextTx:%u\r\n", timeout_us); + // reference tick for uplink schedule: when gateway started beacon + BeaconCtx.sendAt = BeaconCtx.rx_setup_at + BeaconCtx.rx_precession_us; + BeaconCtx.sendAt += BeaconCtx.tx_slot_offset * PING_SLOT_RESOLUTION_us; + _tx_timeout.attach_us(&send_callback, BeaconCtx.sendAt); + mac_printf("sendAt:%llu ", BeaconCtx.sendAt); + + BeaconCtx.rx_setup_at += BEACON_INTERVAL_us; + BeaconCtx.rx_setup_at += compensation; + + BeaconCtx._timeout_rx.attach_us(&OnRxBeaconSetup, BeaconCtx.rx_setup_at); + BeaconCtx._timeout_guard.attach_us(&guard_callback, BeaconCtx.rx_setup_at - BEACON_GUARD_us); if (BeaconCtx.num_missed > 0) { /* restore rx symbol timeout */ - set_beacon_symbol_timeout(BEACON_RX_TIMEOUT_LOCKED); + us_to_nSymbTimeout(BEACON_RX_TIMEOUT_LOCKED_us); } BeaconCtx.num_missed = 0; @@ -1037,82 +1042,32 @@ LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication ); /* check beacon payload */ - uint16_t calc_crc = beacon_crc(payload, 4); - uint16_t rx_crc = payload[4]; - rx_crc |= payload[5] << 8; + uint16_t calc_crc = beacon_crc(Radio::radio.rx_buf, 4); + uint16_t rx_crc = Radio::radio.rx_buf[4]; + rx_crc |= Radio::radio.rx_buf[5] << 8; if (rx_crc == calc_crc) { - unsigned int rx = payload[0]; - rx |= payload[1] << 8; - rx |= payload[2] << 16; - rx |= payload[3] << 24; + unsigned int rx = Radio::radio.rx_buf[0]; + rx |= Radio::radio.rx_buf[1] << 8; + rx |= Radio::radio.rx_buf[2] << 16; + rx |= Radio::radio.rx_buf[3] << 24; if (rx != 0) { - //isr_printf("beacon payload:%08x\r\n", rx); - LoRaMacRxPayload[0] = payload[0]; - LoRaMacRxPayload[1] = payload[1]; - LoRaMacRxPayload[2] = payload[2]; - LoRaMacRxPayload[3] = payload[3]; + //mac_printf("beacon payload:%08x\r\n", rx); McpsIndication.McpsIndication = MCPS_MULTICAST; McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; - McpsIndication.Buffer = LoRaMacRxPayload; + McpsIndication.Buffer = Radio::radio.rx_buf; McpsIndication.BufferSize = 4; McpsIndication.RxData = true; LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); } } else - isr_printf("calc_crc:%04x rx_crc:%04x\r\n", calc_crc, rx_crc); -} - -float get_symbol_period(uint8_t bw, uint8_t sf) + mac_printf("calc_crc:%04x rx_crc:%04x\r\n", calc_crc, rx_crc); +} // ..rx_beacon() + + +#define JOIN_ACCEPT_MAX_SIZE 34 +static void OnRadioRxDone(uint8_t size, float rssi, float snr ) { - //bw:, // 0=125kHz, 1=250kHz, 2=500KHz - float hz; - switch( bw ) - { - //case 0: // 7.8 kHz - // bw = 78e2; - // break; - //case 1: // 10.4 kHz - // bw = 104e2; - // break; - //case 2: // 15.6 kHz - // bw = 156e2; - // break; - //case 3: // 20.8 kHz - // bw = 208e2; - // break; - //case 4: // 31.2 kHz - // bw = 312e2; - // break; - //case 5: // 41.4 kHz - // bw = 414e2; - // break; - //case 6: // 62.5 kHz - // bw = 625e2; - // break; - case 0: // 125 kHz - hz = 125e3; - break; - case 1: // 250 kHz - hz = 250e3; - break; - case 2: // 500 kHz - hz = 500e3; - break; - default: - return 0; - } - - // return symbol period in seconds - return (1 << sf) / hz; -} - -static uint32_t GetRxBandwidth( int8_t datarate ) -{ - return 2; /* always 500KHz */ -} - -static void OnRadioRxDone(unsigned rx_us, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) -{ + uint8_t _jaDecrypted[JOIN_ACCEPT_MAX_SIZE]; LoRaMacHeader_t macHdr; LoRaMacFrameCtrl_t fCtrl; bool skipIndication = false; @@ -1151,106 +1106,118 @@ McpsIndication.DownLinkCounter = 0; McpsIndication.McpsIndication = MCPS_UNCONFIRMED; - Radio.Sleep( ); - - if (expecting_beacon) { - rx_beacon(rx_us, payload, size); - expecting_beacon = false; + Radio::Sleep( ); + + //mac_printf("OnRadioRxDone %u", size); + if (LoRaMacFlags.Bits.expecting_beacon) { + rx_beacon(size); + LoRaMacFlags.Bits.expecting_beacon = false; return; } - macHdr.Value = payload[pktHeaderLen++]; + macHdr.Value = Radio::radio.rx_buf[pktHeaderLen++]; + //mac_printf("mtype:%x\r\n", macHdr.Bits.MType); switch( macHdr.Bits.MType ) { case FRAME_TYPE_JOIN_ACCEPT: - if (IsLoRaMacNetworkJoined) + if (LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) { McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_JOIN_ACCEPT; PrepareRxDoneAbort( ); return; } - LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 ); - - LoRaMacRxPayload[0] = macHdr.Value; - - LoRaMacJoinComputeMic( LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic ); - - micRx |= ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN]; - micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8 ); - micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 ); - micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 ); + LoRaMacJoinDecrypt( Radio::radio.rx_buf + 1, size - 1, LoRaMacAppKey, &_jaDecrypted[1]); + + _jaDecrypted[0] = macHdr.Value; + + LoRaMacJoinComputeMic( _jaDecrypted, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic ); + + micRx |= ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN]; + micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 1] << 8 ); + micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 2] << 16 ); + micRx |= ( ( uint32_t )_jaDecrypted[size - LORAMAC_MFR_LEN + 3] << 24 ); if( micRx == mic ) { - LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey ); - - LoRaMacNetID = ( uint32_t )LoRaMacRxPayload[4]; - LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 ); - LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[6] << 16 ); - - LoRaMacDevAddr = ( uint32_t )LoRaMacRxPayload[7]; - LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[8] << 8 ); - LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[9] << 16 ); - LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[10] << 24 ); + LoRaMacJoinComputeSKeys( LoRaMacAppKey, _jaDecrypted + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey ); + + LoRaMacNetID = ( uint32_t )_jaDecrypted[4]; + LoRaMacNetID |= ( ( uint32_t )_jaDecrypted[5] << 8 ); + LoRaMacNetID |= ( ( uint32_t )_jaDecrypted[6] << 16 ); + + LoRaMacDevAddr = ( uint32_t )_jaDecrypted[7]; + LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[8] << 8 ); + LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[9] << 16 ); + LoRaMacDevAddr |= ( ( uint32_t )_jaDecrypted[10] << 24 ); // DLSettings - LoRaMacParams.Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07; - - LoRaMacParams.ReceiveDelay_us = ( LoRaMacRxPayload[12] & 0x0F ); + LoRaMacParams.Rx1DrOffset = ( _jaDecrypted[11] >> 4 ) & 0x07; + + LoRaMacParams.ReceiveDelay_us = ( _jaDecrypted[12] & 0x0F ); if( LoRaMacParams.ReceiveDelay_us == 0 ) LoRaMacParams.ReceiveDelay_us = RECEIVE_DELAY_us; else LoRaMacParams.ReceiveDelay_us *= 10; - uint16_t beaconTimingDelay = LoRaMacRxPayload[13] & 0xff; - beaconTimingDelay |= LoRaMacRxPayload[14] << 8; - - isr_printf("%lx slots:%x (rxdelay %lu)", LoRaMacDevAddr, beaconTimingDelay, LoRaMacParams.ReceiveDelay_us); - unsigned int now_us = lp_timer.read_us(); - unsigned int us_since_TxDone = now_us - TxDone_us; - unsigned us_to_beacon = ( PING_SLOT_RESOLUTION_us * beaconTimingDelay ); - unsigned timeout_us = us_to_beacon - us_since_TxDone; - BeaconCtx.timeout_rx.attach_us(&OnRxBeaconSetup, timeout_us); - BeaconCtx.timeout_guard.attach_us(&guard_callback, timeout_us - BEACON_GUARD_us); - - BeaconCtx.tx_slot_offset = LoRaMacRxPayload[15]; - BeaconCtx.tx_slot_offset |= LoRaMacRxPayload[16] << 8; - BeaconCtx.periodicity_slots = LoRaMacRxPayload[17]; - BeaconCtx.periodicity_slots |= LoRaMacRxPayload[18] << 8; - - BeaconCtx.LastBeaconRx_us = (us_to_beacon + TxDone_us) - BEACON_INTERVAL_us; - unsigned us_since_beacon_start = now_us - BeaconCtx.LastBeaconRx_us; - int now_slot = (us_since_beacon_start - BEACON_RESERVED_us) / 30000; - int use_slot = BeaconCtx.tx_slot_offset; - while (use_slot < now_slot) - use_slot += BeaconCtx.periodicity_slots; - int slots_now_to_next = use_slot - now_slot; - timeout_us = slots_now_to_next * 30000; - tx_timeout.attach_us(&send_callback, timeout_us); - - isr_printf(" now_slot:%d use_slot:%d timeout_us:%u\r\n", now_slot, use_slot, timeout_us); - isr_printf("us_to_beacon:%u, since_txDone:%u\r\n", us_to_beacon, us_since_TxDone); + uint16_t beaconTimingDelay = _jaDecrypted[13] & 0xff; + beaconTimingDelay |= _jaDecrypted[14] << 8; + + mac_printf("%lx slots:%x (rxdelay %lu)", LoRaMacDevAddr, beaconTimingDelay, LoRaMacParams.ReceiveDelay_us); + { + unsigned us_to_beacon = ( PING_SLOT_RESOLUTION_us * beaconTimingDelay ); + mac_printf(" us_to_beacon:%u ", us_to_beacon); + // time to beacon given as referenced to end of join request uplink + BeaconCtx.rx_setup_at = txDoneAt + us_to_beacon - PPM_BEACON_INTERVAL; + BeaconCtx._timeout_rx.attach_us(&OnRxBeaconSetup, BeaconCtx.rx_setup_at); + BeaconCtx._timeout_guard.attach_us(&guard_callback, BeaconCtx.rx_setup_at - BEACON_GUARD_us); + + mac_printf("beaconIn:%llu\r\n", BeaconCtx.rx_setup_at - BeaconCtx._timeout_rx.read_us()); + } + + BeaconCtx.tx_slot_offset = _jaDecrypted[15]; + BeaconCtx.tx_slot_offset |= _jaDecrypted[16] << 8; + BeaconCtx.periodicity_slots = _jaDecrypted[17]; + BeaconCtx.periodicity_slots |= _jaDecrypted[18] << 8; + + /* nowSlot: now vs previous beacon */ + BeaconCtx.LastBeaconRx_us = BeaconCtx.rx_setup_at - BEACON_INTERVAL_us; + unsigned us_since_last_beacon = _rx_timeout.read_us() - BeaconCtx.LastBeaconRx_us; + unsigned nowSlot = us_since_last_beacon / PING_SLOT_RESOLUTION_us; + unsigned useSlot = BeaconCtx.tx_slot_offset; + while (useSlot < nowSlot) + useSlot += BeaconCtx.periodicity_slots; + + mac_printf("useSlot:%u nowSlot:%u ", useSlot, nowSlot); + BeaconCtx.sendAt = BeaconCtx.LastBeaconRx_us + (useSlot * PING_SLOT_RESOLUTION_us); + mac_printf("sendIn:%u\r\n", BeaconCtx.sendAt - _tx_timeout.read_us()); + _tx_timeout.attach_us(send_callback, BeaconCtx.sendAt); + BeaconCtx.sendOpportunities = 0; + BeaconCtx.state = BEACON_STATE_FIRST_ACQ; BeaconCtx.guard = false; BeaconCtx.num_missed = 0; BeaconCtx.rx_precession_us = 0; - BeaconCtx.last_BeaconRxTimerError_us = -PPM_100_BEACON_INTERVAL; - BeaconCtx.known_working_BeaconRxTimerError_us = -PPM_100_BEACON_INTERVAL; - BeaconCtx.symbol_period_secs = get_symbol_period(GetRxBandwidth(LORAMAC_DEFAULT_DATARATE), Datarates[LORAMAC_DEFAULT_DATARATE]); - // N-ms: slot resolution + minimum for preamble detector + 100ppm fast crystal rxing 12ms early - BeaconCtx.Precess_symbols = TARGET_PRECESSION_US * (BeaconCtx.symbol_period_secs); - BeaconCtx.SymbolTimeout_sec = 0.1 + (BEACON_MIN_SYMBOL_TIMEOUT * BeaconCtx.symbol_period_secs); - BeaconCtx.SymbolTimeout = BeaconCtx.SymbolTimeout_sec / BeaconCtx.symbol_period_secs; + BeaconCtx.last_BeaconRxTimerError_us = -PPM_BEACON_INTERVAL; + BeaconCtx.known_working_BeaconRxTimerError_us = -PPM_BEACON_INTERVAL; + /* first beacon reception needs to open for 30ms timing resolution */ + BeaconCtx.Precess_symbols = ceil(TARGET_PRECESSION_us / BeaconCtx.symbol_period_us); + BeaconCtx.SymbolTimeout_us = PING_SLOT_RESOLUTION_us + (PPM_BEACON_INTERVAL * 2); // error unknown at start + BeaconCtx.nSymbsTimeout = BeaconCtx.SymbolTimeout_us / BeaconCtx.symbol_period_us; + if (BeaconCtx.nSymbsTimeout < MIN_SYMBOL_TIMEOUT) + BeaconCtx.nSymbsTimeout = MIN_SYMBOL_TIMEOUT; + else if (BeaconCtx.nSymbsTimeout > 255) + BeaconCtx.nSymbsTimeout = 255; + mac_printf("startSymbTo:%u ", BeaconCtx.nSymbsTimeout); MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; - IsLoRaMacNetworkJoined = true; + LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = true; LoRaMacParams.ChannelsDatarate_fixed = LoRaMacParamsDefaults.ChannelsDatarate_fixed; } else { MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; - isr_printf("join-mic-fail\r\n"); + mac_printf("join-mic-fail\r\n"); JoinRequestTrials = MaxJoinRequestTrials; // stop trying } LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm ); @@ -1259,10 +1226,10 @@ case FRAME_TYPE_DATA_CONFIRMED_DOWN: case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: { - address = payload[pktHeaderLen++]; - address |= ( (uint32_t)payload[pktHeaderLen++] << 8 ); - address |= ( (uint32_t)payload[pktHeaderLen++] << 16 ); - address |= ( (uint32_t)payload[pktHeaderLen++] << 24 ); + address = Radio::radio.rx_buf[pktHeaderLen++]; + address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 8 ); + address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 16 ); + address |= ( (uint32_t)Radio::radio.rx_buf[pktHeaderLen++] << 24 ); if( address != LoRaMacDevAddr ) { @@ -1295,17 +1262,17 @@ downLinkCounter = DownLinkCounter; } - fCtrl.Value = payload[pktHeaderLen++]; - - sequenceCounter = ( uint16_t )payload[pktHeaderLen++]; - sequenceCounter |= ( uint16_t )payload[pktHeaderLen++] << 8; + fCtrl.Value = Radio::radio.rx_buf[pktHeaderLen++]; + + sequenceCounter = ( uint16_t )Radio::radio.rx_buf[pktHeaderLen++]; + sequenceCounter |= ( uint16_t )Radio::radio.rx_buf[pktHeaderLen++] << 8; appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen; - micRx |= ( uint32_t )payload[size - LORAMAC_MFR_LEN]; - micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 1] << 8 ); - micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 2] << 16 ); - micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 3] << 24 ); + micRx |= ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN]; + micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 1] << 8 ); + micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 2] << 16 ); + micRx |= ( ( uint32_t )Radio::radio.rx_buf[size - LORAMAC_MFR_LEN + 3] << 24 ); sequenceCounterPrev = ( uint16_t )downLinkCounter; sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev ); @@ -1313,7 +1280,7 @@ if( sequenceCounterDiff < ( 1 << 15 ) ) { downLinkCounter += sequenceCounterDiff; - LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic ); + LoRaMacComputeMic( Radio::radio.rx_buf, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic ); if( micRx == mic ) { isMicOk = true; @@ -1323,7 +1290,7 @@ { // check for sequence roll-over uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff; - LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic ); + LoRaMacComputeMic( Radio::radio.rx_buf, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic ); if( micRx == mic ) { isMicOk = true; @@ -1372,7 +1339,7 @@ { if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN ) { - SrvAckRequested = true; + LoRaMacFlags.Bits.SrvAckRequested = true; McpsIndication.McpsIndication = MCPS_CONFIRMED; if( ( DownLinkCounter == downLinkCounter ) && @@ -1388,7 +1355,7 @@ } else { - SrvAckRequested = false; + LoRaMacFlags.Bits.SrvAckRequested = false; McpsIndication.McpsIndication = MCPS_UNCONFIRMED; if( ( DownLinkCounter == downLinkCounter ) && @@ -1422,7 +1389,7 @@ // Process payload and MAC commands if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 ) { - port = payload[appPayloadStartIndex++]; + port = Radio::radio.rx_buf[appPayloadStartIndex++]; frameLen = ( size - 4 ) - appPayloadStartIndex; McpsIndication.Port = port; @@ -1432,16 +1399,17 @@ // Only allow frames which do not have fOpts if( fCtrl.Bits.FOptsLen == 0 ) { - LoRaMacPayloadDecrypt( payload + appPayloadStartIndex, + uint8_t macDecrypt[16]; + LoRaMacPayloadDecrypt( Radio::radio.rx_buf + appPayloadStartIndex, frameLen, nwkSKey, address, DOWN_LINK, downLinkCounter, - LoRaMacRxPayload ); + macDecrypt); // Decode frame payload MAC commands - ProcessMacCommands( LoRaMacRxPayload, 0, frameLen, snr ); + ProcessMacCommands( macDecrypt, 0, frameLen, snr ); } else { @@ -1453,20 +1421,20 @@ if( fCtrl.Bits.FOptsLen > 0 ) { // Decode Options field MAC commands. Omit the fPort. - ProcessMacCommands( payload, 8, appPayloadStartIndex - 1, snr ); + ProcessMacCommands( Radio::radio.rx_buf, 8, appPayloadStartIndex - 1, snr ); } - LoRaMacPayloadDecrypt( payload + appPayloadStartIndex, + LoRaMacPayloadDecrypt( Radio::radio.rx_buf + appPayloadStartIndex, frameLen, appSKey, address, DOWN_LINK, downLinkCounter, - LoRaMacRxPayload ); + rxFRMPayload); if( skipIndication == false ) { - McpsIndication.Buffer = LoRaMacRxPayload; + McpsIndication.Buffer = rxFRMPayload; McpsIndication.BufferSize = frameLen; McpsIndication.RxData = true; } @@ -1477,7 +1445,7 @@ if( fCtrl.Bits.FOptsLen > 0 ) { // Decode Options field MAC commands - ProcessMacCommands( payload, 8, appPayloadStartIndex, snr ); + ProcessMacCommands( Radio::radio.rx_buf, 8, appPayloadStartIndex, snr ); } } @@ -1513,11 +1481,9 @@ break; case FRAME_TYPE_PROPRIETARY: { - memcpy1( LoRaMacRxPayload, &payload[pktHeaderLen], size ); - McpsIndication.McpsIndication = MCPS_PROPRIETARY; McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; - McpsIndication.Buffer = LoRaMacRxPayload; + McpsIndication.Buffer = Radio::radio.rx_buf; McpsIndication.BufferSize = size - pktHeaderLen; LoRaMacFlags.Bits.McpsInd = 1; @@ -1526,7 +1492,7 @@ default: McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE; McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE; - isr_printf("%d:macHdr:%02x(%d,%d) ", size, macHdr.Value, rssi, snr); + mac_printf("%d:macHdr:%02x(%d,%d) ", size, macHdr.Value, rssi, snr); PrepareRxDoneAbort( ); break; } @@ -1534,13 +1500,11 @@ application_callbacks(); -} // ..OnRadioRxDone(); - - +} // ..OnRadioRxDone() static void OnRadioTxTimeout( void ) { - Radio.Sleep( ); + Radio::Sleep( ); McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; @@ -1549,30 +1513,27 @@ static void OnRadioRxError( void ) { - Radio.Sleep( ); - - if (NodeAckRequested) + Radio::Sleep( ); + + if (LoRaMacFlags.Bits.NodeAckRequested) { McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR; } MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR; - if ((lp_timer.read_us() - AggregatedLastTxDoneTime_us) >= RxWindowDelay_us ) - { - LoRaMacFlags.Bits.MacDone = 1; - } + LoRaMacFlags.Bits.MacDone = 1; } static void join_send() { - flags.join_send = 1; + LoRaMacFlags.Bits.join_send = 1; } static void ScheduleTx( void ) { - if (!IsLoRaMacNetworkJoined) - flags.send = 1; // immediately send join asychronously + if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) + LoRaMacFlags.Bits.send = 1; // immediately send join asychronously else LoRaMacFlags.Bits.uplink_pending = 1; // send synchronously } @@ -1583,149 +1544,81 @@ if (JoinRequestTrials < MaxJoinRequestTrials) { LoRaMacHeader_t macHdr; LoRaMacFrameCtrl_t fCtrl; - + if (++Channel == LORA_MAX_NB_CHANNELS) Channel = 0; - isr_printf("<join-ch%u>", Channel); - + mac_printf("<join-ch%u>", Channel); + macHdr.Value = 0; macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ; - + fCtrl.Value = 0; fCtrl.Bits.Adr = 0; - + /* In case of join request retransmissions, the stack must prepare * the frame again, because the network server keeps track of the random * LoRaMacDevNonce values to prevent reply attacks. */ PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 ); - + ScheduleTx(); } else { MlmeConfirm.MlmeRequest = MLME_JOIN; MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm ); } -} +} // ..join_send_bh() static void OnRadioRxTimeout( void ) { - static unsigned LastBeaconRx_us; - - Radio.Sleep( ); - - if (expecting_beacon) { - unsigned next_beacon_expected_us = BEACON_INTERVAL_us; - if (BeaconCtx.state == BEACON_STATE_FIRST_ACQ) { - next_beacon_expected_us -= 1000000; - set_beacon_symbol_timeout(1.000); - } else { - next_beacon_expected_us += BeaconCtx.known_working_BeaconRxTimerError_us; - // for measurement resolution and temperature drift while missing beacons: - next_beacon_expected_us -= 10000; - set_beacon_symbol_timeout(BeaconCtx.SymbolTimeout_sec + 0.025); - } - unsigned now_us = lp_timer.read_us(); - unsigned us_since_rx_setup = now_us - BeaconCtx.RxBeaconSetupAt_us; - unsigned b_timeout_us = next_beacon_expected_us - us_since_rx_setup; - BeaconCtx.timeout_rx.attach_us(&OnRxBeaconSetup, b_timeout_us); - BeaconCtx.timeout_guard.attach_us(&guard_callback, b_timeout_us - BEACON_GUARD_us); - - if (BeaconCtx.num_missed == 0) /* first missed beacon, init our local LastBeaconRx_us */ - LastBeaconRx_us = BeaconCtx.LastBeaconRx_us; - - BeaconCtx.num_missed++; - /***************************************/ - unsigned fake_ThisBeaconRx_us = LastBeaconRx_us + BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us; - unsigned us_since_beacon_start = now_us - fake_ThisBeaconRx_us; - unsigned timeout_us = BEACON_RESERVED_us + (BeaconCtx.tx_slot_offset * 30000) - us_since_beacon_start; - tx_timeout.attach_us(&send_callback, timeout_us); - isr_printf("fake %u\r\n", fake_ThisBeaconRx_us - LastBeaconRx_us); - LastBeaconRx_us = fake_ThisBeaconRx_us; // update our local for next missed beacon - /***************************************/ - -#ifdef DEBUG_GWTX_JUMPER - isr_printf("rx-before-gwtx:%d ", gwtx_rise_us - BeaconCtx.RxBeaconSetupAt_us); -#endif /* DEBUG_GWTX_JUMPER */ - - isr_printf("beacon-rx-timeout %u %u next in %uus (rxing for %u)", BeaconCtx.num_missed, BeaconCtx.SymbolTimeout, b_timeout_us, us_since_rx_setup); - isr_printf(" %u,nextTx:%u\r\n", us_since_beacon_start, timeout_us); - - MlmeIndication.MlmeIndication = MLME_BEACON; - MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_BEACON_LOST; - LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication ); + Radio::Sleep( ); + + if (LoRaMacFlags.Bits.expecting_beacon) { + float ourErrSecs = BeaconCtx.known_working_BeaconRxTimerError_us / 1000000.0; BeaconCtx.guard = false; - expecting_beacon = false; + LoRaMacFlags.Bits.expecting_beacon = false; + + BeaconCtx.rx_setup_at += BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us; + BeaconCtx.rx_setup_at -= (PPM_BEACON_INTERVAL / 4); + us_to_nSymbTimeout(BeaconCtx.SymbolTimeout_us + (PPM_BEACON_INTERVAL / 2)); + mac_printf("beacon timeout ourErr:%f SymbTo:%u\r\n", ourErrSecs, BeaconCtx.nSymbsTimeout); + + BeaconCtx._timeout_rx.attach_us(&OnRxBeaconSetup, BeaconCtx.rx_setup_at); + BeaconCtx._timeout_guard.attach_us(&guard_callback, BeaconCtx.rx_setup_at - BEACON_GUARD_us); + + if (++BeaconCtx.num_missed > BEACONS_MISSED_LIMIT) { + LoRaMacFlags.Bits.reJoin = 1; + } else { + MlmeIndication.MlmeIndication = MLME_BEACON; + MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_BEACON_LOST; + LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication ); + } + + BeaconCtx.sendAt = BeaconCtx.LastBeaconRx_us + ((BEACON_INTERVAL_us + BeaconCtx.known_working_BeaconRxTimerError_us) * BeaconCtx.num_missed); + BeaconCtx.sendAt += BeaconCtx.tx_slot_offset * PING_SLOT_RESOLUTION_us; + _tx_timeout.attach_us(&send_callback, BeaconCtx.sendAt); + } else { if (LoRaMacFlags.Bits.MlmeReq && ( MlmeConfirm.MlmeRequest == MLME_JOIN )) { /* no join accept received: join retry */ - tx_timeout.attach_us(&join_send, (JoinRequestTrials*20000) + randr(0, 70000)); + _tx_timeout.attach_us(&join_send, _tx_timeout.read_us() + (JoinRequestTrials*20000) + randr(0, 70000)); } } - if (NodeAckRequested) + if (LoRaMacFlags.Bits.NodeAckRequested) { McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT; } MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT; LoRaMacFlags.Bits.MacDone = 1; - + application_callbacks(); } // ..OnRadioRxTimeout(); -static void OnRxWindowTimerEventBH() -{ - Radio.Standby( ); - if (expecting_beacon) { - isr_printf("rxwin-during-beacon\r\n"); - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR; - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR; - LoRaMacFlags.Bits.MacDone = 1; - LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm ); - } else { - //RxWindowSetup( LORAMAC_FIRST_CHANNEL + ( Channel * LORAMAC_STEPWIDTH_CHANNEL), RxWindowsParam.Datarate, RxWindowsParam.Bandwidth, RxWindowsParam.RxWindowTimeout, false ); - RxWindowSetup( Channels[Channel].Frequency, RxWindowsParam.Datarate, RxWindowsParam.Bandwidth, RxWindowsParam.RxWindowTimeout, false ); - } -} - -static void OnRxWindowTimerEvent( void ) -{ - flags.rx_win = 1; -} - static void OnAckTimeoutTimerEvent( void ) { } -static bool RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous ) -{ - uint8_t downlinkDatarate = Datarates[datarate]; - RadioModems_t modem; - - if( Radio.GetStatus( ) == RF_IDLE ) - { - Radio.SetChannel( freq ); - - // Store downlink datarate - McpsIndication.RxDatarate = ( uint8_t ) datarate; - - modem = MODEM_LORA; - Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous ); - Radio.SetMaxPayloadLength( MODEM_LORA, 255 ); - - if( rxContinuous == false ) - { - Radio.Rx( LoRaMacParams.MaxRxWindow ); - } - else - { - Radio.Rx( 0 ); // Continuous mode - } - return true; - } - return false; -} - static bool ValueInRange( int8_t value, int8_t min, int8_t max ) { if( ( value >= min ) && ( value <= max ) ) @@ -1907,7 +1800,7 @@ static void ResetMacParameters( void ) { - IsLoRaMacNetworkJoined = false; + LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = false; // Counters UpLinkCounter = 0; @@ -1925,8 +1818,8 @@ LoRaMacParams.Rx1DrOffset = LoRaMacParamsDefaults.Rx1DrOffset; - NodeAckRequested = false; - SrvAckRequested = false; + LoRaMacFlags.Bits.NodeAckRequested = false; + LoRaMacFlags.Bits.SrvAckRequested = false; MacCommandsInNextTx = false; // Reset Multicast downlink counters @@ -1942,14 +1835,13 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ) { uint16_t i; - uint8_t pktHeaderLen = 0; uint32_t mic = 0; const void* payload = fBuffer; uint8_t framePort = fPort; - - LoRaMacBufferPktLen = 0; - - NodeAckRequested = false; + uint8_t LoRaMacTxPayloadLen = 0; + + LoRaMacFlags.Bits.NodeAckRequested = false; + tx_buf_len = 0; if( fBuffer == NULL ) { @@ -1958,57 +1850,55 @@ LoRaMacTxPayloadLen = fBufferSize; - LoRaMacBuffer[pktHeaderLen++] = macHdr->Value; + Radio::radio.tx_buf[tx_buf_len++] = macHdr->Value; switch( macHdr->Bits.MType ) { case FRAME_TYPE_JOIN_REQ: - LoRaMacBufferPktLen = pktHeaderLen; - - memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8 ); - LoRaMacBufferPktLen += 8; - memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacDevEui, 8 ); - LoRaMacBufferPktLen += 8; - - LoRaMacDevNonce = Radio.Random( ); - - LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen++] = ( LoRaMacDevNonce >> 8 ) & 0xFF; - - LoRaMacJoinComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic ); - - LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 8 ) & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 16 ) & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 24 ) & 0xFF; + memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacAppEui, 8 ); + tx_buf_len += 8; + memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 ); + tx_buf_len += 8; + + LoRaMacDevNonce = Radio::Random( ); + + Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF; + + LoRaMacJoinComputeMic( Radio::radio.tx_buf, tx_buf_len & 0xFF, LoRaMacAppKey, &mic ); + + Radio::radio.tx_buf[tx_buf_len++] = mic & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 8 ) & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 16 ) & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 24 ) & 0xFF; break; case FRAME_TYPE_DATA_CONFIRMED_UP: - NodeAckRequested = true; + LoRaMacFlags.Bits.NodeAckRequested = true; //Intentional fallthrough case FRAME_TYPE_DATA_UNCONFIRMED_UP: - if (!IsLoRaMacNetworkJoined) + if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) { return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet } fCtrl->Bits.AdrAckReq = 0; - if( SrvAckRequested == true ) + if( LoRaMacFlags.Bits.SrvAckRequested == true ) { - SrvAckRequested = false; + LoRaMacFlags.Bits.SrvAckRequested = false; fCtrl->Bits.Ack = 1; } - LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF; - LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF; - LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF; - LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF; - - LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value; - - LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF; - LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr ) & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 8 ) & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 16 ) & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 24 ) & 0xFF; + + Radio::radio.tx_buf[tx_buf_len++] = fCtrl->Value; + + Radio::radio.tx_buf[tx_buf_len++] = UpLinkCounter & 0xFF; + Radio::radio.tx_buf[tx_buf_len++] = ( UpLinkCounter >> 8 ) & 0xFF; // Copy the MAC commands which must be re-send into the MAC command buffer memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex ); @@ -2021,10 +1911,10 @@ fCtrl->Bits.FOptsLen += MacCommandsBufferIndex; // Update FCtrl field with new value of OptionsLength - LoRaMacBuffer[0x05] = fCtrl->Value; + Radio::radio.tx_buf[0x05] = fCtrl->Value; for( i = 0; i < MacCommandsBufferIndex; i++ ) { - LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i]; + Radio::radio.tx_buf[tx_buf_len++] = MacCommandsBuffer[i]; } } } @@ -2047,34 +1937,34 @@ if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) ) { - LoRaMacBuffer[pktHeaderLen++] = framePort; + Radio::radio.tx_buf[tx_buf_len++] = framePort; if( framePort == 0 ) { - LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &LoRaMacBuffer[pktHeaderLen] ); + LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &Radio::radio.tx_buf[tx_buf_len] ); } else { - LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &LoRaMacBuffer[pktHeaderLen] ); + LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &Radio::radio.tx_buf[tx_buf_len] ); } } - LoRaMacBufferPktLen = pktHeaderLen + LoRaMacTxPayloadLen; - - LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic ); - - LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen + 1] = ( mic >> 8 ) & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen + 2] = ( mic >> 16 ) & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF; - - LoRaMacBufferPktLen += LORAMAC_MFR_LEN; + tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen; + + LoRaMacComputeMic( Radio::radio.tx_buf, tx_buf_len, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic ); + + Radio::radio.tx_buf[tx_buf_len + 0] = mic & 0xFF; + Radio::radio.tx_buf[tx_buf_len + 1] = ( mic >> 8 ) & 0xFF; + Radio::radio.tx_buf[tx_buf_len + 2] = ( mic >> 16 ) & 0xFF; + Radio::radio.tx_buf[tx_buf_len + 3] = ( mic >> 24 ) & 0xFF; + + tx_buf_len += LORAMAC_MFR_LEN; break; case FRAME_TYPE_PROPRIETARY: if( ( fBuffer != NULL ) && ( LoRaMacTxPayloadLen > 0 ) ) { - memcpy1( LoRaMacBuffer + pktHeaderLen, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen ); - LoRaMacBufferPktLen = pktHeaderLen + LoRaMacTxPayloadLen; + memcpy1( Radio::radio.tx_buf + tx_buf_len, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen ); + tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen; } break; default: @@ -2092,23 +1982,47 @@ txPowerIndex = LoRaMacParams.ChannelsTxPower; txPower = TxPowers[txPowerIndex]; - Radio.SetTxContinuousWave( Channels[Channel].Frequency, txPower, timeout ); + Radio::SetTxContinuousWave( Channels[Channel].Frequency, txPower, timeout ); return LORAMAC_STATUS_OK; } LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power ) { - Radio.SetTxContinuousWave( frequency, power, timeout ); + Radio::SetTxContinuousWave( frequency, power, timeout ); return LORAMAC_STATUS_OK; } void seconds() { - isr_printf("second\r\n"); + mac_printf("second\r\n"); +} + +void on_dio0_top_half(us_timestamp_t dio0_at) +{ + mac_printf("dio0th\r\n"); } +unsigned get_symbol_period_us(uint8_t sf) +{ + float bwMHz = LORA_BANDWIDTH_KHZ / 1000.0; + // return symbol period in microseconds + return (1 << sf) / bwMHz; +} + +const RadioEvents_t rev = { + /* Dio0_top_half */ on_dio0_top_half, + /* TxDone_topHalf */ NULL, + /* TxDone_botHalf */ OnRadioTxDone_bh, + /* TxTimeout */ OnRadioTxTimeout, + /* RxDone */ OnRadioRxDone, + /* RxTimeout */ OnRadioRxTimeout, + /* RxError */ OnRadioRxError, + /* FhssChangeChannel */NULL, + /* CadDone */ NULL +}; + LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks ) { if( primitives == NULL ) @@ -2128,18 +2042,20 @@ LoRaMacFlags.Value = 0; - LoRaMacDeviceClass = CLASS_A; - JoinRequestTrials = 0; MaxJoinRequestTrials = 255; + BeaconCtx.symbol_period_us = get_symbol_period_us(Datarates[LORAMAC_DEFAULT_DATARATE]); // Reset to defaults LoRaMacParamsDefaults.ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER; LoRaMacParamsDefaults.ChannelsDatarate_fixed = LORAMAC_DEFAULT_DATARATE; - LoRaMacParamsDefaults.SystemMaxRxError = 10; - LoRaMacParamsDefaults.MinRxSymbols = 6; // TODO XXX increase + LoRaMacParamsDefaults.SystemMaxRxError_ms = 20; + LoRaMacParamsDefaults.MinRxSymbols = (LoRaMacParamsDefaults.SystemMaxRxError_ms * 1000) / BeaconCtx.symbol_period_us; + if (LoRaMacParamsDefaults.MinRxSymbols < MIN_SYMBOL_TIMEOUT) + LoRaMacParamsDefaults.MinRxSymbols = MIN_SYMBOL_TIMEOUT; + LoRaMacParamsDefaults.MaxRxWindow = MAX_RX_WINDOW; LoRaMacParamsDefaults.ReceiveDelay_us = RECEIVE_DELAY_us; @@ -2156,7 +2072,7 @@ } // Init parameters which are not set in function ResetMacParameters - LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError; + LoRaMacParams.SystemMaxRxError_ms = LoRaMacParamsDefaults.SystemMaxRxError_ms; LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols; LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow; LoRaMacParams.ReceiveDelay_us = LoRaMacParamsDefaults.ReceiveDelay_us; @@ -2166,30 +2082,22 @@ ResetMacParameters( ); // Initialize Radio driver - RadioEvents.TxDone = OnRadioTxDone; - RadioEvents.RxDone = OnRadioRxDone; - RadioEvents.RxError = OnRadioRxError; - RadioEvents.TxTimeout = OnRadioTxTimeout; - RadioEvents.RxTimeout = OnRadioRxTimeout; - Radio.Init( &RadioEvents ); + Radio::Init(&rev); + // lpt started later. lpt will have smaller number. + lpt_offset = _rx_timeout.read_us() - Radio::lpt.read_us(); + mac_printf("lpt_offset:%d\r\n", lpt_offset); // Random seed initialization - srand1( Radio.Random( ) ); + srand1( Radio::Random( ) ); PublicNetwork = true; - Radio.SetPublicNetwork( PublicNetwork ); - Radio.Sleep( ); - - lp_timer.start(); - - RxWindowsParam = ComputeRxWindowParameters(LORAMAC_DEFAULT_DATARATE, LoRaMacParams.SystemMaxRxError); - -#ifdef DEBUG_GWTX_JUMPER - gwtx_pin.rise(&gwtx_pin_callback); -#endif + Radio::SetPublicNetwork( PublicNetwork ); + Radio::Sleep( ); + + RxWindowsParam = ComputeRxWindowParameters(LORAMAC_DEFAULT_DATARATE, LoRaMacParams.SystemMaxRxError_ms); return LORAMAC_STATUS_OK; -} +} // ..LoRaMacInitialization() LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo ) { @@ -2200,7 +2108,7 @@ return LORAMAC_STATUS_PARAMETER_INVALID; } - txInfo->CurrentPayloadSize = 255; + txInfo->CurrentPayloadSize = LORAMAC_PHY_MAXPAYLOAD; if( txInfo->CurrentPayloadSize >= fOptLen ) { @@ -2225,14 +2133,9 @@ switch( mibGet->Type ) { - case MIB_DEVICE_CLASS: - { - mibGet->Param.Class = LoRaMacDeviceClass; - break; - } case MIB_NETWORK_JOINED: { - mibGet->Param.IsNetworkJoined = IsLoRaMacNetworkJoined; + mibGet->Param.IsNetworkJoined = LoRaMacFlags.Bits.IsLoRaMacNetworkJoined; break; } case MIB_NET_ID: @@ -2297,7 +2200,7 @@ } case MIB_SYSTEM_MAX_RX_ERROR: { - mibGet->Param.SystemMaxRxError = LoRaMacParams.SystemMaxRxError; + mibGet->Param.SystemMaxRxError_ms = LoRaMacParams.SystemMaxRxError_ms; break; } case MIB_MIN_RX_SYMBOLS: @@ -2324,33 +2227,13 @@ switch( mibSet->Type ) { - case MIB_DEVICE_CLASS: - { - LoRaMacDeviceClass = mibSet->Param.Class; - switch( LoRaMacDeviceClass ) - { - case CLASS_A: - { - // Set the radio into sleep to setup a defined state - Radio.Sleep( ); - break; - } - case CLASS_B: - { - break; - } - case CLASS_D: - isr_printf("TODO MIB_DEVICE_CLASS:D\r\n"); - break; - } - break; - } case MIB_NETWORK_JOINED: { - IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined; - if (!IsLoRaMacNetworkJoined) { - BeaconCtx.timeout_rx.detach(); - BeaconCtx.timeout_guard.detach(); + LoRaMacFlags.Bits.IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined; + if (!LoRaMacFlags.Bits.IsLoRaMacNetworkJoined) { + mac_printf("beaconDetach\r\n"); + BeaconCtx._timeout_rx.detach(); + BeaconCtx._timeout_guard.detach(); BeaconCtx.state = BEACON_STATE_NONE; } break; @@ -2394,7 +2277,7 @@ case MIB_PUBLIC_NETWORK: { PublicNetwork = mibSet->Param.EnablePublicNetwork; - Radio.SetPublicNetwork( PublicNetwork ); + Radio::SetPublicNetwork( PublicNetwork ); break; } case MIB_CHANNELS_NB_REP: @@ -2453,7 +2336,7 @@ } case MIB_SYSTEM_MAX_RX_ERROR: { - LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError = mibSet->Param.SystemMaxRxError; + LoRaMacParams.SystemMaxRxError_ms = LoRaMacParamsDefaults.SystemMaxRxError_ms = mibSet->Param.SystemMaxRxError_ms; break; } case MIB_MIN_RX_SYMBOLS: @@ -2583,12 +2466,12 @@ macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ; ResetMacParameters( ); - expecting_beacon = false; + LoRaMacFlags.Bits.expecting_beacon = false; BeaconCtx.state = BEACON_STATE_NONE; Channel = 0; // start with first channel - isr_printf("<ch0>"); - isr_printf("mlme-join-send ch%u\r\n", Channel); + mac_printf("<ch0>"); + mac_printf("mlme-join-send ch%u\r\n", Channel); status = Send( &macHdr, 0, NULL, 0 ); break; } @@ -2621,7 +2504,7 @@ if( status != LORAMAC_STATUS_OK ) { - NodeAckRequested = false; + LoRaMacFlags.Bits.NodeAckRequested = false; LoRaMacFlags.Bits.MlmeReq = 0; } @@ -2681,17 +2564,17 @@ break; } - if( readyToSend == true ) + if (readyToSend) { status = Send( &macHdr, fPort, fBuffer, fBufferSize ); - if( status == LORAMAC_STATUS_OK ) + if (status == LORAMAC_STATUS_OK) { McpsConfirm.McpsRequest = mcpsRequest->Type; LoRaMacFlags.Bits.McpsReq = 1; } else { - NodeAckRequested = false; + LoRaMacFlags.Bits.NodeAckRequested = false; } } @@ -2711,30 +2594,17 @@ void LoRaMacTestSetChannel( uint8_t channel ) { - isr_printf("set-testch%u\r\n", channel); + mac_printf("set-testch%u\r\n", channel); Channel = channel; } static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError ) { - RxConfigParams_t rxConfigParams = { 0, 0, 0, 0 }; + RxConfigParams_t rxConfigParams = { 0, 0 }; double tSymbol = 0.0; rxConfigParams.Datarate = datarate; - switch( Bandwidths[datarate] ) - { - default: - case 125000: - rxConfigParams.Bandwidth = 0; - break; - case 250000: - rxConfigParams.Bandwidth = 1; - break; - case 500000: - rxConfigParams.Bandwidth = 2; - break; - } #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) if( datarate == DR_7 ) @@ -2744,33 +2614,38 @@ else #endif { // LoRa - tSymbol = ( ( double )( 1 << Datarates[datarate] ) / ( double )Bandwidths[datarate] ) * 1e3; + tSymbol = ( ( double )( 1 << Datarates[datarate] ) / LORA_BANDWIDTH_KHZ ) * 1e3; } rxConfigParams.RxWindowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * LoRaMacParams.MinRxSymbols - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), LoRaMacParams.MinRxSymbols ); // Computed number of symbols - - rxConfigParams.RxOffset = ( int32_t )ceil( ( 4.0 * tSymbol ) - ( ( rxConfigParams.RxWindowTimeout * tSymbol ) / 2.0 ) - RADIO_WAKEUP_TIME ); + mac_printf("RxWindowTimeout:%u\r\n", rxConfigParams.RxWindowTimeout); return rxConfigParams; } void LoRaMacBottomHalf() { - if (flags.rx_win) { - OnRxWindowTimerEventBH(); - flags.rx_win = 0; + if (LoRaMacFlags.Bits.join_send) { + join_send_bh(); + LoRaMacFlags.Bits.join_send = 0; } - if (flags.join_send) { - join_send_bh(); - flags.join_send = 0; + if (LoRaMacFlags.Bits.send) { + send_bh(); + LoRaMacFlags.Bits.send = 0; } - if (flags.beacon_setup) { - OnRxBeaconSetupBH(); - flags.beacon_setup = 0; + + if (LoRaMacFlags.Bits.reJoin) { + MlmeReq_t mlmeReq; + mlmeReq.Type = MLME_JOIN; + + mlmeReq.Req.Join.DevEui = LoRaMacDevEui; + mlmeReq.Req.Join.AppEui = LoRaMacAppEui; + mlmeReq.Req.Join.AppKey = LoRaMacAppKey; + mlmeReq.Req.Join.NbTrials = 255; + + if (LoRaMacMlmeRequest(&mlmeReq) == LORAMAC_STATUS_OK) + LoRaMacFlags.Bits.reJoin = 0; } - if (flags.send) { - send_bh(); - flags.send = 0; - } - Radio.BottomHalf(); + + Radio::service(); }