LMiC库能够经过一组API函数(API functions),运行时函数(run-time functions),回调函数(callback functions),和全局LMIC数据结构(global LMIC data structure) 四种方式来实现访问。
LMiC库提供了一个简单的基于事件的编程模型,其中全部协议事件都是调度到应用程序的onEvent()回调函数;为了释放应用程序诸如定时或中断等细节,该库具备内置的运行时环境来处理定时器排队和Job管理。全部协议事件都是经过回调onEvent()函数来实现的。
LMiC库由两个宏来定义编程
#define LMIC_VERSION_MAJOR 1 #define LMIC_VERSION_MINOR 5
LMIC库外部协议接口定义都包含在lmic.h中,以供外部使用。api
#include “lmic.h”
struct lmic_t { // Radio settings TX/RX (also accessed by HAL) ostime_t txend; ostime_t rxtime; u4_t freq; s1_t rssi; s1_t snr; rps_t rps; u1_t rxsyms; u1_t dndr; s1_t txpow; // dBm osjob_t osjob; // Channel scheduling #if defined(CFG_eu868) band_t bands[MAX_BANDS]; u4_t channelFreq[MAX_CHANNELS]; u2_t channelDrMap[MAX_CHANNELS]; u2_t channelMap; #elif defined(CFG_us915) 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 chRnd; // channel randomizer #endif u1_t txChnl; // channel for next TX u1_t globalDutyRate; // max rate: 1/2^k ostime_t globalDutyAvail; // time device can send again u4_t netid; // current network id (~0 - none) u2_t opmode; 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 s2_t drift; // last measured drift s2_t lastDriftDiff; s2_t maxDriftDiff; u1_t pendTxPort; u1_t pendTxConf; // confirmed data u1_t pendTxLen; // +0x80 = confirmed u1_t pendTxData[MAX_LEN_PAYLOAD]; u2_t devNonce; // last generated nonce u1_t nwkKey[16]; // network session key u1_t artKey[16]; // application router session key devaddr_t devaddr; u4_t seqnoDn; // device level down stream seqno u4_t seqnoUp; u1_t dnConf; // dn frame confirm pending: LORA::FCT_ACK or 0 s1_t adrAckReq; // counter until we reset data rate (0=off) u1_t adrChanged; u1_t margin; bit_t ladrAns; // link adr adapt answer pending bit_t devsAns; // device status answer pending u1_t adrEnabled; u1_t moreData; // NWK has more data pending bit_t dutyCapAns; // have to ACK duty cycle settings u1_t snchAns; // answer set new channel // 2nd RX window (after up stream) u1_t dn2Dr; u4_t dn2Freq; u1_t dn2Ans; // 0=no answer pend, 0x80+ACKs // Class B state u1_t missedBcns; // unable to track last N beacons u1_t bcninfoTries; // how often to try (scan mode only) u1_t pingSetAns; // answer set cmd and ACK bits rxsched_t ping; // pingable setup // 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]; u1_t bcnChnl; u1_t bcnRxsyms; // ostime_t bcnRxtime; bcninfo_t bcninfo; // Last received beacon info }; //! \var struct lmic_t LMIC //! The state of LMIC MAC layer is encapsulated in this variable. DECLARE_LMIC; //!< \internal
// purpose of receive window - lmic_t.rxState enum { RADIO_RST=0, RADIO_TX=1, RADIO_RX=2, RADIO_RXON=3 };
void os_radio (u1_t mode) { hal_disableIRQs(); switch (mode) { case RADIO_RST: opmode(OPMODE_SLEEP); // put radio to sleep break; case RADIO_TX: // transmit frame now starttx(); // buf=LMIC.frame, len=LMIC.dataLen break; case RADIO_RX: // receive frame now (exactly at rxtime) startrx(RXMODE_SINGLE); // buf=LMIC.frame, time=LMIC.rxtime, timeout=LMIC.rxsyms break; case RADIO_RXON:// start scanning for beacon now startrx(RXMODE_SCAN); // buf=LMIC.frame break; } hal_enableIRQs(); }
// Netid values / lmic_t.netid enum { NETID_NONE=(int)~0U, NETID_MASK=(int)0xFFFFFF };
// 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_DNW1 = 0x01, // received in 1st DN slot TXRX_DNW2 = 0x02, // received in 2dn DN slot TXRX_PING = 0x04 }; // received in a scheduled RX slot
对于EV_RXCOMPLETE和EV_TXCOMPLETE事件,txrxFlags字段定义了如下标志:
TXRX_ACK :上行确认帧被确认(与TXRX_NACK互斥)
TXRX_NACK:上行确认帧未被确认(与TXRX_ACK互斥)
TXRX_PORT:端口字段包含在接收帧中
TXRX_DNW1:在第一个下行接收窗口中接收(与TXRX_DNW2互斥)
TXRX_DNW2:在第二个下行接收窗口中接收(与TXRX_DNW1互斥)
TXRX_PING:在预约的RX Slot中接收(Beacon帧)数组
对于EV_TXCOMPLETE事件,这些字段具备如下值:
对于EV_RXCOMPLETE事件,这些字段具备如下值:
服务器
// 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 };
// Radio parameter set (encodes SF/BW/CR/IH/NOCRC) typedef u2_t rps_t; inline rps_t makeRps (sf_t sf, bw_t bw, cr_t cr, int ih, int nocrc) { return sf | (bw<<3) | (cr<<5) | (nocrc?(1<<7):0) | ((ih&0xFF)<<8); }
LMiC库提供一组API函数来控制MAC状态并触发协议动做。
事件回调函数的事件类型由enum定义session
// 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 };
重置MAC状态。会话和挂起的数据传输将被丢弃。数据结构
当即开始加入网络。若是没有会话,将被其余API函数隐含地调用已经创建了将生成事件EV_JOINING和EV_JOINED或EV_JOIN_FAILED。app
检查是否能够链接其余网络。假如没有找到新的网络当前网络的会话将保留。将生成EV_JOINED或EV_REJOIN_FAILED事件。dom
设置静态会话参数。替代经过加入网络动态创建会话,能够提供预计算的会话参数。恢复预先计算的会话参数,帧序列计数器(LMIC.seqnoUp和LMIC.seqnoDn)必须恢复为他们的最新值。函数
建立具备指定发射功率和占空比(1 / txcap)属性的新频段。
使用指定的频率建立给定频段的新信道,并容许数据速率在数据速率位掩码(1 << DRx)中定义。
禁用指定的信道。
启用/禁用数据速率适配。若是是移动设备应该关闭。
启用/禁用连接检查验证。默认状况下启用链路检查模式,并按期使用验证网络链接。仅当会话创建时才必须调用。
设置数据速率和传输功率。只有在禁用数据速率调整时才应使用。
在下一个可能的时间准备上行数据传输。假设pendTxData,pendTxLen,pendTxPort和pendTxConf已经设置好了。数据长度为LMIC.pendTxLen,数组LMIC.pendTxData[]中的数据将被发送到LMIC.pendTxPort端口。若是LMIC.pendTxConf使能,服务器将回复确认帧。当通讯完成后将生成EV_TXCOMPLETE事件,即数据发送完成而且收到最终下行数据或已收到确认帧。
在下一个可能的时间准备上行数据传输,方便功能LMIC_setTxData()。若是数据为NULL,则将使用LMIC.pendTxData []中的数据。
删除以前为上行传输准备的数据。
启用信标(beacon帧)跟踪。对于LMIC.bcninfoTries=tryBcnInfo的值为0表示开始当即扫描beacon帧;非零值指定试图查询服务器准确beacon帧到达时间的次数。查询请求将在下一个上行帧内发送(不会另外生成帧)。若是没有应答接收扫描将开始。第一个beacon帧将生成EV_BEACON_FOUND或EV_SCAN_TIMEOUT事件,随后的beacon帧将生成EV_BEACON_TRACKED,EV_BEACON_MISSED或EV_LOST_TSYNC事件。
禁用beacon帧跟踪。beacon帧将再也不被跟踪,所以也将禁用ping
启用ping和设置下行监听间隔。 Ping将在下一个上行帧启用(不会生成新帧)。监听间隔为2 ^ intvExp秒,intvExp(LMIC.ping.intvExp)的有效值是0-7。此API函数须要经过网络服务器创建的有效会话LMIC_startJoining()或LMIC_setSession()函数(见2.2和2.4节)。若是beacon帧跟踪还没有启用,扫描将当即开始。为了不扫描,经过使用前一次调用非零参数的LMIC_enableTracking()能够更有效地定位beacon帧。除了LMIC_enableTracking()提到的事件以外,每当在ping slot(ping时槽)中接收到下行数据时将生成EV_RXCOMPLETE事件。
中止监听下行数据。按期侦听被禁用,但beacon仍将被追踪。为了中止beacon跟踪,beacon须要调用LMIC_disableTracking()。
尽快发送一个空的上行MAC帧。可能被用来表示信号活性或者要传输等待中的MAC选项,并打开接收窗口。
中止全部MAC活动。随后,MAC须要经过调用LMIC_reset();若是有新的协议动做则须要从新发起。
void LMIC_init (void) { LMIC.opmode = OP_SHUTDOWN; }