From 6c6412034043d39f0fd163bad949e2cecfd3a14c Mon Sep 17 00:00:00 2001 From: sessionm21 Date: Thu, 14 May 2020 19:33:57 +0100 Subject: [PATCH] code fits on device --- collar.cpp | 27 +- lmic.h | 737 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 752 insertions(+), 12 deletions(-) create mode 100644 lmic.h diff --git a/collar.cpp b/collar.cpp index e44b643..f844268 100644 --- a/collar.cpp +++ b/collar.cpp @@ -326,6 +326,9 @@ void do_send(osjob_t* j){ float latitude = 123; float longitude = 456; + + latitude = 44.558308; + longitude = -123.28341; memcpy(buffer+3, (void*)&latitude, 4); memcpy(buffer+8, (void*)&longitude, 4); @@ -438,22 +441,22 @@ void loop() { state = WAITING_GPS; } else if(state == WAITING_GPS) { - //int got_data = - read_gps(); + int got_data = + read_gps(); /**************************************************** * loading bar animation ***************************************************/ - //if(got_data) { - // if(loopCounter%100==0) - // Serial.write('.'); - if(loopCounter>PROGRESS_BAR_COUNT*100) { - // clear_line(); - // loopCounter=0; - // - state = VERIFYING_GPS; + if(got_data) { + if(loopCounter%100==0) + Serial.write('.'); + if(loopCounter>PROGRESS_BAR_COUNT*100) { + clear_line(); + loopCounter=0; + + state = VERIFYING_GPS; + } + loopCounter++; } - // loopCounter++; - //} } else if(state == VERIFYING_GPS) { /**************************************************** diff --git a/lmic.h b/lmic.h new file mode 100644 index 0000000..9de9e06 --- /dev/null +++ b/lmic.h @@ -0,0 +1,737 @@ +/* + * Copyright (c) 2014-2016 IBM Corporation. + * Copyright (c) 2016 Matthijs Kooijman. + * Copyright (c) 2016-2020 MCCI Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//! @file +//! @brief LMIC API + +#ifndef _lmic_h_ +#define _lmic_h_ + +#include "oslmic.h" +#include "lorabase.h" + +#if LMIC_DEBUG_LEVEL > 0 || LMIC_X_DEBUG_LEVEL > 0 +# if defined(LMIC_DEBUG_INCLUDE) +# define LMIC_STRINGIFY_(x) #x +# define LMIC_STRINGIFY(x) LMIC_STRINGIFY_(x) +# include LMIC_STRINGIFY(LMIC_DEBUG_INCLUDE) +# endif +# ifdef LMIC_DEBUG_PRINTF_FN + extern void LMIC_DEBUG_PRINTF_FN(const char *f, ...); +# endif // ndef LMIC_DEBUG_PRINTF_FN +#endif + +// if LMIC_DEBUG_PRINTF is now defined, just use it. This lets you do anything +// you like with a sufficiently crazy header file. +#if LMIC_DEBUG_LEVEL > 0 +# ifndef LMIC_DEBUG_PRINTF +// otherwise, check whether someone configured a print-function to be used, +// and use it if so. +# ifdef LMIC_DEBUG_PRINTF_FN +# define LMIC_DEBUG_PRINTF(f, ...) LMIC_DEBUG_PRINTF_FN(f, ## __VA_ARGS__) +# ifndef LMIC_DEBUG_INCLUDE // If you use LMIC_DEBUG_INCLUDE, put the declaration in there + void LMIC_DEBUG_PRINTF_FN(const char *f, ...); +# endif // ndef LMIC_DEBUG_INCLUDE +# else // ndef LMIC_DEBUG_PRINTF_FN +// if there's no other info, just use printf. In a pure Arduino environment, +// that's what will happen. +# include +# define LMIC_DEBUG_PRINTF(f, ...) printf(f, ## __VA_ARGS__) +# endif // ndef LMIC_DEBUG_PRINTF_FN +# endif // ndef LMIC_DEBUG_PRINTF +# ifndef LMIC_DEBUG_FLUSH +# ifdef LMIC_DEBUG_FLUSH_FN +# define LMIC_DEBUG_FLUSH() LMIC_DEBUG_FLUSH_FN() +# else // ndef LMIC_DEBUG_FLUSH_FN +// if there's no other info, assume that flush is not needed. +# define LMIC_DEBUG_FLUSH() do { ; } while (0) +# endif // ndef LMIC_DEBUG_FLUSH_FN +# endif // ndef LMIC_DEBUG_FLUSH +#else // LMIC_DEBUG_LEVEL == 0 +// If debug level is zero, printf and flush expand to nothing. +# define LMIC_DEBUG_PRINTF(f, ...) do { ; } while (0) +# define LMIC_DEBUG_FLUSH() do { ; } while (0) +#endif // LMIC_DEBUG_LEVEL == 0 + +// +// LMIC_X_DEBUG_LEVEL enables additional, special print functions for debugging +// RSSI features. This is used sparingly. +#if LMIC_X_DEBUG_LEVEL > 0 +# ifdef LMIC_DEBUG_PRINTF_FN +# define LMIC_X_DEBUG_PRINTF(f, ...) LMIC_DEBUG_PRINTF_FN(f, ## __VA_ARGS__) +# else +# error "LMIC_DEBUG_PRINTF_FN must be defined for LMIC_X_DEBUG_LEVEL > 0." +# endif +#else +# define LMIC_X_DEBUG_PRINTF(f, ...) do {;} while(0) +#endif + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +// LMIC version -- this is ths IBM LMIC version +#define LMIC_VERSION_MAJOR 1 +#define LMIC_VERSION_MINOR 6 +#define LMIC_VERSION_BUILD 1468577746 + +// Arduino LMIC version +#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \ + ((((major)*UINT32_C(1)) << 24) | (((minor)*UINT32_C(1)) << 16) | (((patch)*UINT32_C(1)) << 8) | (((local)*UINT32_C(1)) << 0)) + +#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 2, 0, 0) /* v3.2.0 */ + +#define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \ + ((((v)*UINT32_C(1)) >> 24u) & 0xFFu) + +#define ARDUINO_LMIC_VERSION_GET_MINOR(v) \ + ((((v)*UINT32_C(1)) >> 16u) & 0xFFu) + +#define ARDUINO_LMIC_VERSION_GET_PATCH(v) \ + ((((v)*UINT32_C(1)) >> 8u) & 0xFFu) + +#define ARDUINO_LMIC_VERSION_GET_LOCAL(v) \ + ((v) & 0xFFu) + +//! Only For Antenna Tuning Tests ! +//#define CFG_TxContinuousMode 1 + +// since this was annouunced as the API variable, we keep it. But it's not used, +// MAX_LEN_FRAME is what the code uses. +enum { MAX_FRAME_LEN = MAX_LEN_FRAME }; //!< Library cap on max frame length + +enum { TXCONF_ATTEMPTS = 8 }; //!< Transmit attempts for confirmed frames +enum { MAX_MISSED_BCNS = (2 * 60 * 60 + 127) / 128 }; //!< threshold for dropping out of class B, triggering rejoin requests + // note that we need 100 ppm timing accuracy for + // this, to keep the timing error to +/- 700ms. +enum { MAX_RXSYMS = 350 }; // Stop tracking beacon if sync error grows beyond this. A 0.4% clock error + // at SF9.125k means 512 ms; one sybol is 4.096 ms, + // so this needs to be at least 125 for an STM32L0. + // And for 100ppm clocks and 2 hours of beacon misses, + // this needs to accomodate 1.4 seconds of error at + // 4.096 ms/sym or at least 342 symbols. + +enum { LINK_CHECK_CONT = 0 , // continue with this after reported dead link + LINK_CHECK_DEAD = 32 , // after this UP frames and no response to ack from NWK assume link is dead (ADR_ACK_DELAY) + LINK_CHECK_UNJOIN_MIN = LINK_CHECK_DEAD + 4, // this is the minimum value of LINK_CHECK_UNJOIN if we parameterize + LINK_CHECK_UNJOIN = LINK_CHECK_DEAD + (3 * 240), // after this many UP frames and no response, switch to join (by default) + LINK_CHECK_INIT = -64 , // UP frame count until we ask for ack (ADR_ACK_LIMIT) + LINK_CHECK_OFF =-128 }; // link check disabled + +enum { TIME_RESYNC = 6*128 }; // secs +enum { TXRX_GUARD_ms = 6000 }; // msecs - don't start TX-RX transaction before beacon +enum { JOIN_GUARD_ms = 9000 }; // msecs - don't start Join Req/Acc transaction before beacon +enum { TXRX_BCNEXT_secs = 2 }; // secs - earliest start after beacon time +enum { RETRY_PERIOD_secs = 3 }; // secs - random period for retrying a confirmed send + +#if CFG_LMIC_EU_like // EU868 spectrum ==================================================== + +enum { MAX_CHANNELS = 16 }; //!< Max supported channels +enum { MAX_BANDS = 4 }; + +enum { LIMIT_CHANNELS = (1<<4) }; // EU868 will never have more channels +//! \internal +struct band_t { + u2_t txcap; // duty cycle limitation: 1/txcap + s1_t txpow; // maximum TX power + u1_t lastchnl; // last used channel + ostime_t avail; // channel is blocked until this time +}; +TYPEDEF_xref2band_t; //!< \internal + +struct lmic_saved_adr_state_s { + u4_t channelFreq[MAX_CHANNELS]; + u2_t channelMap; +}; + +#elif CFG_LMIC_US_like // US915 spectrum ================================================= + +enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable + +struct lmic_saved_adr_state_s { + u2_t channelMap[(72+MAX_XCHANNELS+15)/16]; // enabled bits + u2_t activeChannels125khz; + u2_t activeChannels500khz; +}; + +#endif // ========================================================================== + +typedef struct lmic_saved_adr_state_s lmic_saved_adr_state_t; + +// Keep in sync with evdefs.hpp::drChange +enum { DRCHG_SET, DRCHG_NOJACC, DRCHG_NOACK, DRCHG_NOADRACK, DRCHG_NWKCMD, DRCHG_FRAMESIZE }; +enum { KEEP_TXPOW = -128 }; + + +#if !defined(DISABLE_PING) +//! \internal +struct rxsched_t { + dr_t dr; + u1_t intvExp; // 0..7 + u1_t slot; // runs from 0 to 128 + rxsyms_t rxsyms; + ostime_t rxbase; + ostime_t rxtime; // start of next spot + u4_t freq; +}; +TYPEDEF_xref2rxsched_t; //!< \internal +#endif // !DISABLE_PING + + +#if !defined(DISABLE_BEACONS) +//! Parsing and tracking states of beacons. +enum { BCN_NONE = 0x00, //!< No beacon received + BCN_PARTIAL = 0x01, //!< Only first (common) part could be decoded (info,lat,lon invalid/previous) + BCN_FULL = 0x02, //!< Full beacon decoded + BCN_NODRIFT = 0x04, //!< No drift value measured yet + BCN_NODDIFF = 0x08 }; //!< No differential drift measured yet +//! Information about the last and previous beacons. +struct bcninfo_t { + ostime_t txtime; //!< Time when the beacon was sent + u4_t time; //!< GPS time in seconds of last beacon (received or surrogate) + s4_t lat; //!< Lat field of last beacon (valid only if BCN_FULL set) + s4_t lon; //!< Lon field of last beacon (valid only if BCN_FULL set) + s1_t rssi; //!< Adjusted RSSI value of last received beacon + s1_t snr; //!< Scaled SNR value of last received beacon + u1_t flags; //!< Last beacon reception and tracking states. See BCN_* values. + // + u1_t info; //!< Info field of last beacon (valid only if BCN_FULL set) +}; +#endif // !DISABLE_BEACONS + +// purpose of receive window - lmic_t.rxState +enum { RADIO_RST=0, RADIO_TX=1, RADIO_RX=2, RADIO_RXON=3, RADIO_TX_AT=4, }; +// Netid values / lmic_t.netid +enum { NETID_NONE=(int)~0U, NETID_MASK=(int)0xFFFFFF }; +// MAC operation modes (lmic_t.opmode). +enum { OP_NONE = 0x0000, + OP_SCAN = 0x0001, // radio scan to find a beacon + OP_TRACK = 0x0002, // track my networks beacon (netid) + OP_JOINING = 0x0004, // device joining in progress (blocks other activities) + OP_TXDATA = 0x0008, // TX user data (buffered in pendTxData) + OP_POLL = 0x0010, // send empty UP frame to ACK confirmed DN/fetch more DN data + OP_REJOIN = 0x0020, // occasionally send JOIN REQUEST + OP_SHUTDOWN = 0x0040, // prevent MAC from doing anything + OP_TXRXPEND = 0x0080, // TX/RX transaction pending + OP_RNDTX = 0x0100, // prevent TX lining up after a beacon + OP_PINGINI = 0x0200, // pingable is initialized and scheduling active + OP_PINGABLE = 0x0400, // we're pingable + OP_NEXTCHNL = 0x0800, // find a new channel + OP_LINKDEAD = 0x1000, // link was reported as dead + OP_TESTMODE = 0x2000, // developer test mode + OP_UNJOIN = 0x4000, // unjoin and rejoin on next engineUpdate(). +}; +// TX-RX transaction flags - report back to user +enum { TXRX_ACK = 0x80, // confirmed UP frame was acked + TXRX_NACK = 0x40, // confirmed UP frame was not acked + TXRX_NOPORT = 0x20, // set if a frame with a port was RXed, clr if no frame/no port + TXRX_PORT = 0x10, // set if a frame with a port was RXed, LMIC.frame[LMIC.dataBeg-1] => port + TXRX_LENERR = 0x08, // set if frame was discarded due to length error. + TXRX_PING = 0x04, // received in a scheduled RX slot + TXRX_DNW2 = 0x02, // received in 2dn DN slot + TXRX_DNW1 = 0x01, // received in 1st DN slot +}; + +// Event types for event callback +enum _ev_t { EV_SCAN_TIMEOUT=1, EV_BEACON_FOUND, + EV_BEACON_MISSED, EV_BEACON_TRACKED, EV_JOINING, + EV_JOINED, EV_RFU1, EV_JOIN_FAILED, EV_REJOIN_FAILED, + EV_TXCOMPLETE, EV_LOST_TSYNC, EV_RESET, + EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE, EV_SCAN_FOUND, + EV_TXSTART, EV_TXCANCELED, EV_RXSTART, EV_JOIN_TXCOMPLETE }; +typedef enum _ev_t ev_t; + +// this macro can be used to initalize a normal table of event strings +#define LMIC_EVENT_NAME_TABLE__INIT \ + "<>", \ + "EV_SCAN_TIMEOUT", "EV_BEACON_FOUND", \ + "EV_BEACON_MISSED", "EV_BEACON_TRACKED", "EV_JOINING", \ + "EV_JOINED", "EV_RFU1", "EV_JOIN_FAILED", "EV_REJOIN_FAILED", \ + "EV_TXCOMPLETE", "EV_LOST_TSYNC", "EV_RESET", \ + "EV_RXCOMPLETE", "EV_LINK_DEAD", "EV_LINK_ALIVE", "EV_SCAN_FOUND", \ + "EV_TXSTART", "EV_TXCANCELED", "EV_RXSTART", "EV_JOIN_TXCOMPLETE" + +// if working on an AVR (or worried about it), you can use this multi-zero +// string and put this in a single const F() string. Index through this +// counting up from 0, until you get to the entry you want or to an +// entry that begins with a \0. +#define LMIC_EVENT_NAME_MULTISZ__INIT \ + "<>\0" \ + "EV_SCAN_TIMEOUT\0" "EV_BEACON_FOUND\0" \ + "EV_BEACON_MISSED\0" "EV_BEACON_TRACKED\0" "EV_JOINING\0" \ + "EV_JOINED\0" "EV_RFU1\0" "EV_JOIN_FAILED\0" "EV_REJOIN_FAILED\0" \ + "EV_TXCOMPLETE\0" "EV_LOST_TSYNC\0" "EV_RESET\0" \ + "EV_RXCOMPLETE\0" "EV_LINK_DEAD\0" "EV_LINK_ALIVE\0" "EV_SCAN_FOUND\0" \ + "EV_TXSTART\0" "EV_TXCANCELED\0" "EV_RXSTART\0" "EV_JOIN_TXCOMPLETE\0" + +enum { + LMIC_ERROR_SUCCESS = 0, + LMIC_ERROR_TX_BUSY = -1, + LMIC_ERROR_TX_TOO_LARGE = -2, + LMIC_ERROR_TX_NOT_FEASIBLE = -3, + LMIC_ERROR_TX_FAILED = -4, +}; + +typedef int lmic_tx_error_t; + +#define LMIC_ERROR_NAME__INIT \ + "LMIC_ERROR_SUCCESS", \ + "LMIC_ERROR_TX_BUSY", \ + "LMIC_ERROR_TX_TOO_LARGE", \ + "LMIC_ERROR_TX_NOT_FEASIBLE", \ + "LMIC_ERROR_TX_FAILED" + +#define LMIC_ERROR_NAME_MULTISZ__INIT \ + "LMIC_ERROR_SUCCESS\0" \ + "LMIC_ERROR_TX_BUSY\0" \ + "LMIC_ERROR_TX_TOO_LARGE\0" \ + "LMIC_ERROR_TX_NOT_FEASIBLE\0" \ + "LMIC_ERROR_TX_FAILED" + +enum { + LMIC_BEACON_ERROR_INVALID = -2, + LMIC_BEACON_ERROR_WRONG_NETWORK = -1, + LMIC_BEACON_ERROR_SUCCESS_PARTIAL = 0, + LMIC_BEACON_ERROR_SUCCESS_FULL = 1, +}; + +typedef s1_t lmic_beacon_error_t; + +static inline bit_t LMIC_BEACON_SUCCESSFUL(lmic_beacon_error_t e) { + return e < 0; +} + +// LMIC_CFG_max_clock_error_ppm +#if !defined(LMIC_CFG_max_clock_error_ppm) +# define LMIC_CFG_max_clock_error_ppm 2000 /* max clock error: 0.2% (2000 ppm) */ +#endif + + +enum { + // This value represents 100% error in LMIC.clockError + MAX_CLOCK_ERROR = 65536, + //! \brief maximum clock error that users can specify: 2000 ppm (0.2%). + //! \details This is the limit for clock error, unless LMIC_ENABLE_arbitrary_clock_error is set. + //! The default is 4,000 ppm, which is .004, or 0.4%; this is what you get on an + //! STM32L0 running with the HSI oscillator after cal. If your clock error is bigger, + //! usually you want to calibrate it so that millis() and micros() are reasonably + //! accurate. Important: do not use clock error to compensate for late serving + //! of the LMIC. If you see that LMIC.radio.rxlate_count is increasing, you need + //! to adjust your application logic so the LMIC gets serviced promptly when a + //! Class A downlink (or beacon) is pending. + LMIC_kMaxClockError_ppm = 4000, +}; + +// callbacks for client alerts. +// types and functions are always defined, to reduce #ifs in example code and libraries. +typedef void LMIC_ABI_STD lmic_rxmessage_cb_t(void *pUserData, uint8_t port, const uint8_t *pMessage, size_t nMessage); +typedef void LMIC_ABI_STD lmic_txmessage_cb_t(void *pUserData, int fSuccess); +typedef void LMIC_ABI_STD lmic_event_cb_t(void *pUserData, ev_t e); + +// network time request callback function +// defined unconditionally, because APIs and types can't change based on config. +// This is called when a time-request succeeds or when we get a downlink +// without time request, "completing" the pending time request. +typedef void LMIC_ABI_STD lmic_request_network_time_cb_t(void *pUserData, int flagSuccess); + +// how the network represents time. +typedef u4_t lmic_gpstime_t; + +// rather than deal with 1/256 second tick, we adjust ostime back +// (as it's high res) to match tNetwork. +typedef struct lmic_time_reference_s lmic_time_reference_t; + +struct lmic_time_reference_s { + // our best idea of when we sent the uplink (end of packet). + ostime_t tLocal; + // the network's best idea of when we sent the uplink. + lmic_gpstime_t tNetwork; +}; + +enum lmic_request_time_state_e { + lmic_RequestTimeState_idle = 0, // we're not doing anything + lmic_RequestTimeState_tx, // we want to tx a time request on next uplink + lmic_RequestTimeState_rx, // we have tx'ed, next downlink completes. + lmic_RequestTimeState_success // we sucessfully got time. +}; + +typedef u1_t lmic_request_time_state_t; + +enum lmic_engine_update_state_e { + lmic_EngineUpdateState_idle = 0, // engineUpdate is idle. + lmic_EngineUpdateState_busy = 1, // engineUpdate is busy, but has not been reentered. + lmic_EngineUpdateState_again = 2, // engineUpdate is busy, and has to be evaluated again. +}; + +typedef u1_t lmic_engine_update_state_t; + +/* + +Structure: lmic_client_data_t + +Function: + Holds LMIC client data that must live through LMIC_reset(). + +Description: + There are a variety of client registration linkage items that + must live through LMIC_reset(), because LMIC_reset() is called + at frame rollover time. We group them together into a structure + to make copies easy. + +*/ + +//! abstract type for collection of client data that survives LMIC_reset(). +typedef struct lmic_client_data_s lmic_client_data_t; + +//! contents of lmic_client_data_t +struct lmic_client_data_s { + + /* pointer-width things come first */ +#if LMIC_ENABLE_DeviceTimeReq + lmic_request_network_time_cb_t *pNetworkTimeCb; //! call-back routine for network time + void *pNetworkTimeUserData; //! call-back data for network time. +#endif + +#if LMIC_ENABLE_user_events + lmic_event_cb_t *eventCb; //! user-supplied callback function for events. + void *eventUserData; //! data for eventCb + lmic_rxmessage_cb_t *rxMessageCb; //! user-supplied message-received callback + void *rxMessageUserData; //! data for rxMessageCb + lmic_txmessage_cb_t *txMessageCb; //! transmit-complete message handler; reset on each tx complete. + void *txMessageUserData; //! data for txMessageCb. +#endif // LMIC_ENABLE_user_events + + /* next we have things that are (u)int32_t */ + /* none at the moment */ + + /* next we have things that are (u)int16_t */ + + u2_t clockError; //! Inaccuracy in the clock. CLOCK_ERROR_MAX represents +/-100% error + + /* finally, things that are (u)int8_t */ + /* none at the moment */ +}; + +/* + +Structure: lmic_radio_data_t + +Function: + Holds LMIC radio driver. + +Description: + Eventually this will be used for all portable things for the radio driver, + but for now it's where we can start to add things. + +*/ + +typedef struct lmic_radio_data_s lmic_radio_data_t; + +struct lmic_radio_data_s { + // total os ticks of accumulated delay error. Can overflow! + ostime_t rxlate_ticks; + // number of rx late launches. + unsigned rxlate_count; + // total os ticks of accumulated tx delay error. Can overflow! + ostime_t txlate_ticks; + // number of tx late launches. + unsigned txlate_count; +}; + +/* + +Structure: lmic_t + +Function: + Provides the instance data for the LMIC. + +*/ + +struct lmic_t { + // client setup data, survives LMIC_reset(). + lmic_client_data_t client; + + // the OS job object. pointer alignment. + osjob_t osjob; + +#if !defined(DISABLE_BEACONS) + bcninfo_t bcninfo; // Last received beacon info +#endif + +#if !defined(DISABLE_PING) + rxsched_t ping; // pingable setup +#endif + + // the radio driver portable context + lmic_radio_data_t radio; + + /* (u)int32_t things */ + + // Radio settings TX/RX (also accessed by HAL) + ostime_t txend; + ostime_t rxtime; + + // LBT info + ostime_t lbt_ticks; // ticks to listen + + u4_t freq; + + ostime_t globalDutyAvail; // time device can send again + + u4_t netid; // current network id (~0 - none) + devaddr_t devaddr; + u4_t seqnoDn; // device level down stream seqno + u4_t seqnoUp; + u4_t dn2Freq; + +#if !defined(DISABLE_BEACONS) + ostime_t bcnRxtime; +#endif + +#if LMIC_ENABLE_DeviceTimeReq + // put here for alignment, to reduce RAM use. + ostime_t localDeviceTime; // the LMIC.txend value for last DeviceTimeAns + lmic_gpstime_t netDeviceTime; // the netDeviceTime for lastDeviceTimeAns + // zero ==> not valid. +#endif // LMIC_ENABLE_DeviceTimeReq + + // Channel scheduling -- very much private +#if CFG_LMIC_EU_like + band_t bands[MAX_BANDS]; + u4_t channelFreq[MAX_CHANNELS]; +#if !defined(DISABLE_MCMD_DlChannelReq) + u4_t channelDlFreq[MAX_CHANNELS]; +#endif + // bit map of enabled datarates for each channel + u2_t channelDrMap[MAX_CHANNELS]; + u2_t channelMap; +#elif CFG_LMIC_US_like + u4_t xchFreq[MAX_XCHANNELS]; // extra channel frequencies (if device is behind a repeater) + u2_t xchDrMap[MAX_XCHANNELS]; // extra channel datarate ranges ---XXX: ditto + u2_t channelMap[(72+MAX_XCHANNELS+15)/16]; // enabled bits + u2_t activeChannels125khz; + u2_t activeChannels500khz; +#endif + + /* (u)int16_t things */ + rps_t rps; // radio parameter selections: SF, BW, CodingRate, NoCrc, implicit hdr + u2_t opmode; // engineUpdate() operating mode flags + u2_t devNonce; // last generated nonce + + s2_t adrAckReq; // counter for link integrity tracking (LINK_CHECK_OFF=off) + +#if !defined(DISABLE_BEACONS) + s2_t drift; // last measured drift + s2_t lastDriftDiff; + s2_t maxDriftDiff; + rxsyms_t bcnRxsyms; // +#endif + + /* (u)int8_t things */ + lmic_engine_update_state_t engineUpdateState; // state of the engineUpdate() evaluator. + s1_t rssi; + s1_t snr; // LMIC.snr is SNR times 4 + rxsyms_t rxsyms; // symbols for receive timeout. + u1_t dndr; + s1_t txpow; // transmit dBm (administrative) + s1_t radio_txpow; // the radio driver's copy of txpow, in dB limited by adrTxPow, and + // also adjusted for EIRP/antenna gain considerations. + // This is just the radio's idea of power. So if you are + // controlling EIRP, and you have 3 dB antenna gain, this + // needs to reduced by 3 dB. + s1_t lbt_dbmax; // max permissible dB on our channel (eg -80) + + u1_t txChnl; // channel for next TX + u1_t globalDutyRate; // max rate: 1/2^k + + u1_t upRepeat; // configured up repeat + s1_t adrTxPow; // ADR adjusted TX power + u1_t datarate; // current data rate + u1_t errcr; // error coding rate (used for TX only) + u1_t rejoinCnt; // adjustment for rejoin datarate + + u1_t upRepeatCount; // current up-repeat + bit_t initBandplanAfterReset; // cleared by LMIC_reset(), set by first join. See issue #244 + + u1_t pendTxPort; + u1_t pendTxConf; // confirmed data + u1_t pendTxLen; // count of bytes in pendTxData. + u1_t pendTxData[MAX_LEN_PAYLOAD]; + + u1_t pendMacLen; // number of bytes of pending Mac response data + bit_t pendMacPiggyback; // received on port 0 or piggyback? + // response data if piggybacked + u1_t pendMacData[LWAN_FCtrl_FOptsLen_MAX]; + + u1_t nwkKey[16]; // network session key + u1_t artKey[16]; // application router session key + + u1_t dnConf; // dn frame confirm pending: LORA::FCT_ACK or 0 + u1_t lastDnConf; // downlink with seqnoDn-1 requested confirmation + u1_t adrChanged; + + u1_t rxDelay; // Rx delay after TX + + u1_t margin; + s1_t devAnsMargin; // SNR value between -32 and 31 (inclusive) for the last successfully received DevStatusReq command + u1_t adrEnabled; + u1_t moreData; // NWK has more data pending +#if LMIC_ENABLE_TxParamSetupReq + u1_t txParam; // the saved TX param byte. +#endif +#if LMIC_ENABLE_DeviceTimeReq + lmic_request_time_state_t txDeviceTimeReqState; // current state, initially idle. + u1_t netDeviceTimeFrac; // updated on any DeviceTimeAns. +#endif + + // rx1DrOffset is the offset from uplink to downlink datarate + u1_t rx1DrOffset; // captured from join. zero by default. + + // 2nd RX window (after up stream) + u1_t dn2Dr; +#if !defined(DISABLE_MCMD_RXParamSetupReq) + u1_t dn2Ans; // 0=no answer pend, 0x80+ACKs +#endif +#if !defined(DISABLE_MCMD_DlChannelReq) + u1_t macDlChannelAns; // 0 ==> no answer pending, 0x80+ACK bits +#endif +#if !defined(DISABLE_MCMD_RXTimingSetupReq) + bit_t macRxTimingSetupAns; // 0 ==> no answer pend, non-zero inserts response. +#endif + + // Class B state +#if !defined(DISABLE_BEACONS) + u1_t missedBcns; // unable to track last N beacons + u1_t bcninfoTries; // how often to try (scan mode only) +#endif + // Public part of MAC state + u1_t txCnt; + u1_t txrxFlags; // transaction flags (TX-RX combo) + u1_t dataBeg; // 0 or start of data (dataBeg-1 is port) + u1_t dataLen; // 0 no data or zero length data, >0 byte count of data + u1_t frame[MAX_LEN_FRAME]; + +#if !defined(DISABLE_BEACONS) + u1_t bcnChnl; +#endif + + u1_t noRXIQinversion; + u1_t saveIrqFlags; // last LoRa IRQ flags +}; + +//! \var struct lmic_t LMIC +//! The state of LMIC MAC layer is encapsulated in this variable. +DECLARE_LMIC; //!< \internal + +//! Construct a bit map of allowed datarates from drlo to drhi (both included). +#define DR_RANGE_MAP(drlo,drhi) (((u2_t)0xFFFF<<(drlo)) & ((u2_t)0xFFFF>>(15-(drhi)))) +bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap); +bit_t LMIC_setupChannel (u1_t channel, u4_t freq, u2_t drmap, s1_t band); +bit_t LMIC_disableChannel (u1_t channel); +bit_t LMIC_enableSubBand(u1_t band); +bit_t LMIC_enableChannel(u1_t channel); +bit_t LMIC_disableSubBand(u1_t band); +bit_t LMIC_selectSubBand(u1_t band); + +void LMIC_setDrTxpow (dr_t dr, s1_t txpow); // set default/start DR/txpow +void LMIC_setAdrMode (bit_t enabled); // set ADR mode (if mobile turn off) + +#if !defined(DISABLE_JOIN) +bit_t LMIC_startJoining (void); +void LMIC_tryRejoin (void); +void LMIC_unjoin (void); +void LMIC_unjoinAndRejoin (void); +#endif + +void LMIC_shutdown (void); +void LMIC_init (void); +void LMIC_reset (void); +void LMIC_clrTxData (void); +void LMIC_setTxData (void); +void LMIC_setTxData_strict(void); +lmic_tx_error_t LMIC_setTxData2(u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed); +lmic_tx_error_t LMIC_setTxData2_strict(u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed); +lmic_tx_error_t LMIC_sendWithCallback(u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed, lmic_txmessage_cb_t *pCb, void *pUserData); +lmic_tx_error_t LMIC_sendWithCallback_strict(u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed, lmic_txmessage_cb_t *pCb, void *pUserData); +void LMIC_sendAlive (void); + +#if !defined(DISABLE_BEACONS) +bit_t LMIC_enableTracking (u1_t tryBcnInfo); +void LMIC_disableTracking (void); +#endif + +#if !defined(DISABLE_PING) +void LMIC_stopPingable (void); +void LMIC_setPingable (u1_t intvExp); +#endif + +void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey); +void LMIC_setLinkCheckMode (bit_t enabled); +void LMIC_setClockError(u2_t error); + +u4_t LMIC_getSeqnoUp (void); +u4_t LMIC_setSeqnoUp (u4_t); +void LMIC_getSessionKeys (u4_t *netid, devaddr_t *devaddr, xref2u1_t nwkKey, xref2u1_t artKey); + +void LMIC_requestNetworkTime(lmic_request_network_time_cb_t *pCallbackfn, void *pUserData); +int LMIC_getNetworkTimeReference(lmic_time_reference_t *pReference); + +int LMIC_registerRxMessageCb(lmic_rxmessage_cb_t *pRxMessageCb, void *pUserData); +int LMIC_registerEventCb(lmic_event_cb_t *pEventCb, void *pUserData); + +// APIs for client half of compliance. +typedef u1_t lmic_compliance_rx_action_t; + +enum lmic_compliance_rx_action_e { + LMIC_COMPLIANCE_RX_ACTION_PROCESS = 0, // process this message normally + LMIC_COMPLIANCE_RX_ACTION_START, // enter compliance mode, discard this message + LMIC_COMPLIANCE_RX_ACTION_IGNORE, // continue in compliance mode, discard this message + LMIC_COMPLIANCE_RX_ACTION_END // exit compliance mode, discard this message +}; + +lmic_compliance_rx_action_t LMIC_complianceRxMessage(u1_t port, const u1_t *pMessage, size_t nMessage); + +// Declare onEvent() function, to make sure any definition will have the +// C conventions, even when in a C++ file. +#if LMIC_ENABLE_onEvent +DECL_ON_LMIC_EVENT; +#endif /* LMIC_ENABLE_onEvent */ + +// Special APIs - for development or testing +// !!!See implementation for caveats!!! + +#ifdef __cplusplus +} // extern "C" +#endif + +// names for backward compatibility +#include "lmic_compat.h" + +#endif // _lmic_h_