first commit

This commit is contained in:
Dominik Kuhn 2023-12-09 09:25:45 +01:00
commit 31950351c0
28 changed files with 7326 additions and 0 deletions

5
.gitignore vendored Executable file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
.vscode/extensions.json vendored Executable file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

6
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"files.associations": {
"stm32l0xx_hal.h": "c",
"lmic.h": "c"
}
}

1
README.md Normal file
View File

@ -0,0 +1 @@
# MiniPill LoRa LMIC STM32Cube

39
include/README Executable file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

64
include/debug.h Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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.
*/
#include "oslmic.h"
// intialize debug library
void debug_init (void);
// set LED state
void debug_led (int val);
// write character to USART
void debug_char (char c);
// write byte as two hex digits to USART
void debug_hex (u1_t b);
// write buffer as hex dump to USART
void debug_buf (const u1_t* buf, int len);
// write 32-bit integer as eight hex digits to USART
void debug_uint (u4_t v);
// write 32-bit integer as signed decimal digits to USART
void debug_int (s4_t v);
// write nul-terminated string to USART
void debug_str (const char* str);
// write LMiC event name to USART
void debug_event (int ev);
// write label and 32-bit value as hex to USART
void debug_val (const char* label, u4_t val);
// write label and 32-bit value as signed decimal to USART
void debug_valdec (const char* label, s4_t val);
// convert integer 'val' to ASCII string (bin/oct/dec/hex/base36)
// store string at 'buf', return number of characters written
int debug_fmt (char* buf, int max, s4_t val, int base, int width, char pad);

104
include/hal.h Normal file
View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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.
*/
#ifndef _hal_hpp_
#define _hal_hpp_
#include "oslmic.h"
/*
* initialize hardware (IO, SPI, TIMER, IRQ).
*/
void hal_init (void);
/*
* drive radio NSS pin (0=low, 1=high).
*/
void hal_pin_nss (u1_t val);
/*
* drive radio RX/TX pins (0=rx, 1=tx).
*/
void hal_pin_rxtx (u1_t val);
/*
* control radio RST pin (0=low, 1=high, 2=floating)
*/
void hal_pin_rst (u1_t val);
/*
* perform 8-bit SPI transaction with radio.
* - write given byte 'outval'
* - read byte and return value
*/
u1_t hal_spi (u1_t outval);
/*
* disable all CPU interrupts.
* - might be invoked nested
* - will be followed by matching call to hal_enableIRQs()
*/
void hal_disableIRQs (void);
/*
* enable CPU interrupts.
*/
void hal_enableIRQs (void);
/*
* put system and CPU in low-power mode, sleep until interrupt.
*/
void hal_sleep (void);
/*
* return 32-bit system time in ticks.
*/
u4_t hal_ticks (void);
/*
* busy-wait until specified timestamp (in ticks) is reached.
*/
void hal_waitUntil (u4_t time);
/*
* check and rewind timer for target time.
* - return 1 if target time is close
* - otherwise rewind timer for target time or full period and return 0
*/
u1_t hal_checkTimer (u4_t targettime);
/*
* perform fatal failure action.
* - called by assertions
* - action could be HALT or reboot
*/
void hal_failed (void);
void LmicTimer_IRQHandler ();
#endif // _hal_hpp_

290
include/lmic.h Normal file
View File

@ -0,0 +1,290 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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"
// LMIC version
#define LMIC_VERSION_MAJOR 1
#define LMIC_VERSION_MINOR 6
#define LMIC_VERSION_BUILD 1468577746
//! Only For Antenna Tuning Tests !
//#define CFG_TxContinuousMode 1
enum { MAX_FRAME_LEN = 64 }; //!< Library cap on max frame length
enum { TXCONF_ATTEMPTS = 8 }; //!< Transmit attempts for confirmed frames
enum { MAX_MISSED_BCNS = 20 }; // threshold for triggering rejoin requests
enum { MAX_RXSYMS = 100 }; // stop tracking beacon beyond this
enum { LINK_CHECK_CONT = 12 , // continue with this after reported dead link
LINK_CHECK_DEAD = 24 , // after this UP frames and no response from NWK assume link is dead
LINK_CHECK_INIT = -12 , // UP frame count until we inc datarate
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 defined(CFG_eu868) // 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
#elif defined(CFG_us915) // US915 spectrum =================================================
enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable
enum { MAX_TXPOW_125kHz = 30 };
#endif // ==========================================================================
// Keep in sync with evdefs.hpp::drChange
enum { DRCHG_SET, DRCHG_NOJACC, DRCHG_NOACK, DRCHG_NOADRACK, DRCHG_NWKCMD };
enum { KEEP_TXPOW = -128 };
//! \internal
struct rxsched_t {
u1_t dr;
u1_t intvExp; // 0..7
u1_t slot; // runs from 0 to 128
u1_t rxsyms;
ostime_t rxbase;
ostime_t rxtime; // start of next spot
u4_t freq;
};
TYPEDEF_xref2rxsched_t; //!< \internal
//! 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
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.
u4_t time; //!< GPS time in seconds of last beacon (received or surrogate)
//
u1_t info; //!< Info field of last beacon (valid only if BCN_FULL set)
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)
};
// purpose of receive window - lmic_t.rxState
enum { RADIO_RST=0, RADIO_TX=1, RADIO_RX=2, RADIO_RXON=3 };
// 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
};
// 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
// 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 };
typedef enum _ev_t ev_t;
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 rxDelay; // Rx delay after TX
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
u1_t noRXIQinversion;
};
//! \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))))
#if defined(CFG_eu868)
enum { BAND_MILLI=0, BAND_CENTI=1, BAND_DECI=2, BAND_AUX=3 };
bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap);
#endif
bit_t LMIC_setupChannel (u1_t channel, u4_t freq, u2_t drmap, s1_t band);
void LMIC_disableChannel (u1_t channel);
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)
bit_t LMIC_startJoining (void);
void LMIC_shutdown (void);
void LMIC_init (void);
void LMIC_reset (void);
void LMIC_clrTxData (void);
void LMIC_setTxData (void);
int LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed);
void LMIC_sendAlive (void);
bit_t LMIC_enableTracking (u1_t tryBcnInfo);
void LMIC_disableTracking (void);
void LMIC_stopPingable (void);
void LMIC_setPingable (u1_t intvExp);
void LMIC_tryRejoin (void);
void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey);
void LMIC_setLinkCheckMode (bit_t enabled);
// Special APIs - for development or testing
// !!!See implementation for caveats!!!
#endif // _lmic_h_

400
include/lorabase.h Normal file
View File

@ -0,0 +1,400 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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.
*/
#ifndef _lorabase_h_
#define _lorabase_h_
// ================================================================================
// BEG: Keep in sync with lorabase.hpp
//
enum _cr_t { CR_4_5=0, CR_4_6, CR_4_7, CR_4_8 };
enum _sf_t { FSK=0, SF7, SF8, SF9, SF10, SF11, SF12, SFrfu };
enum _bw_t { BW125=0, BW250, BW500, BWrfu };
typedef u1_t cr_t;
typedef u1_t sf_t;
typedef u1_t bw_t;
typedef u1_t dr_t;
// Radio parameter set (encodes SF/BW/CR/IH/NOCRC)
typedef u2_t rps_t;
TYPEDEF_xref2rps_t;
enum { ILLEGAL_RPS = 0xFF };
enum { DR_PAGE_EU868 = 0x00 };
enum { DR_PAGE_US915 = 0x10 };
// Global maximum frame length
enum { STD_PREAMBLE_LEN = 8 };
enum { MAX_LEN_FRAME = 64 };
enum { LEN_DEVNONCE = 2 };
enum { LEN_ARTNONCE = 3 };
enum { LEN_NETID = 3 };
enum { DELAY_JACC1 = 5 }; // in secs
enum { DELAY_DNW1 = 1 }; // in secs down window #1
enum { DELAY_EXTDNW2 = 1 }; // in secs
enum { DELAY_JACC2 = DELAY_JACC1+(int)DELAY_EXTDNW2 }; // in secs
enum { DELAY_DNW2 = DELAY_DNW1 +(int)DELAY_EXTDNW2 }; // in secs down window #1
enum { BCN_INTV_exp = 7 };
enum { BCN_INTV_sec = 1<<BCN_INTV_exp };
enum { BCN_INTV_ms = BCN_INTV_sec*1000L };
enum { BCN_INTV_us = BCN_INTV_ms*1000L };
enum { BCN_RESERVE_ms = 2120 }; // space reserved for beacon and NWK management
enum { BCN_GUARD_ms = 3000 }; // end of beacon period to prevent interference with beacon
enum { BCN_SLOT_SPAN_ms = 30 }; // 2^12 reception slots a this span
enum { BCN_WINDOW_ms = BCN_INTV_ms-(int)BCN_GUARD_ms-(int)BCN_RESERVE_ms };
enum { BCN_RESERVE_us = 2120000 };
enum { BCN_GUARD_us = 3000000 };
enum { BCN_SLOT_SPAN_us = 30000 };
#if defined(CFG_eu868) // ==============================================
enum _dr_eu868_t { DR_SF12=0, DR_SF11, DR_SF10, DR_SF9, DR_SF8, DR_SF7, DR_SF7B, DR_FSK, DR_NONE };
enum { DR_DFLTMIN = DR_SF7 };
enum { DR_PAGE = DR_PAGE_EU868 };
// Default frequency plan for EU 868MHz ISM band
// Bands:
// g1 : 1% 14dBm
// g2 : 0.1% 14dBm
// g3 : 10% 27dBm
// freq band datarates
enum { EU868_F1 = 868100000, // g1 SF7-12
EU868_F2 = 868300000, // g1 SF7-12 FSK SF7/250
EU868_F3 = 868500000, // g1 SF7-12
EU868_F4 = 868850000, // g2 SF7-12
EU868_F5 = 869050000, // g2 SF7-12
EU868_F6 = 869525000, // g3 SF7-12
EU868_J4 = 864100000, // g2 SF7-12 used during join
EU868_J5 = 864300000, // g2 SF7-12 ditto
EU868_J6 = 864500000, // g2 SF7-12 ditto
};
enum { EU868_FREQ_MIN = 863000000,
EU868_FREQ_MAX = 870000000 };
enum { CHNL_PING = 5 };
enum { FREQ_PING = EU868_F6 }; // default ping freq
enum { DR_PING = DR_SF9 }; // default ping DR
enum { CHNL_DNW2 = 5 };
enum { FREQ_DNW2 = EU868_F6 };
enum { DR_DNW2 = DR_SF12 };
enum { CHNL_BCN = 5 };
enum { FREQ_BCN = EU868_F6 };
enum { DR_BCN = DR_SF9 };
enum { AIRTIME_BCN = 144384 }; // micros
enum {
// Beacon frame format EU SF9
OFF_BCN_NETID = 0,
OFF_BCN_TIME = 3,
OFF_BCN_CRC1 = 7,
OFF_BCN_INFO = 8,
OFF_BCN_LAT = 9,
OFF_BCN_LON = 12,
OFF_BCN_CRC2 = 15,
LEN_BCN = 17
};
#elif defined(CFG_us915) // =========================================
enum _dr_us915_t { DR_SF10=0, DR_SF9, DR_SF8, DR_SF7, DR_SF8C, DR_NONE,
// Devices behind a router:
DR_SF12CR=8, DR_SF11CR, DR_SF10CR, DR_SF9CR, DR_SF8CR, DR_SF7CR };
enum { DR_DFLTMIN = DR_SF8C };
enum { DR_PAGE = DR_PAGE_US915 };
// Default frequency plan for US 915MHz
enum { US915_125kHz_UPFBASE = 902300000,
US915_125kHz_UPFSTEP = 200000,
US915_500kHz_UPFBASE = 903000000,
US915_500kHz_UPFSTEP = 1600000,
US915_500kHz_DNFBASE = 923300000,
US915_500kHz_DNFSTEP = 600000
};
enum { US915_FREQ_MIN = 902000000,
US915_FREQ_MAX = 928000000 };
enum { CHNL_PING = 0 }; // used only for default init of state (follows beacon - rotating)
enum { FREQ_PING = US915_500kHz_DNFBASE + CHNL_PING*US915_500kHz_DNFSTEP }; // default ping freq
enum { DR_PING = DR_SF10CR }; // default ping DR
enum { CHNL_DNW2 = 0 };
enum { FREQ_DNW2 = US915_500kHz_DNFBASE + CHNL_DNW2*US915_500kHz_DNFSTEP };
enum { DR_DNW2 = DR_SF12CR };
enum { CHNL_BCN = 0 }; // used only for default init of state (rotating beacon scheme)
enum { DR_BCN = DR_SF10CR };
enum { AIRTIME_BCN = 72192 }; // micros
enum {
// Beacon frame format US SF10
OFF_BCN_NETID = 0,
OFF_BCN_TIME = 3,
OFF_BCN_CRC1 = 7,
OFF_BCN_INFO = 9,
OFF_BCN_LAT = 10,
OFF_BCN_LON = 13,
OFF_BCN_RFU1 = 16,
OFF_BCN_CRC2 = 17,
LEN_BCN = 19
};
#endif // ===================================================
enum {
// Join Request frame format
OFF_JR_HDR = 0,
OFF_JR_ARTEUI = 1,
OFF_JR_DEVEUI = 9,
OFF_JR_DEVNONCE = 17,
OFF_JR_MIC = 19,
LEN_JR = 23
};
enum {
// Join Accept frame format
OFF_JA_HDR = 0,
OFF_JA_ARTNONCE = 1,
OFF_JA_NETID = 4,
OFF_JA_DEVADDR = 7,
OFF_JA_RFU = 11,
OFF_JA_DLSET = 11,
OFF_JA_RXDLY = 12,
OFF_CFLIST = 13,
LEN_JA = 17,
LEN_JAEXT = 17+16
};
enum {
// Data frame format
OFF_DAT_HDR = 0,
OFF_DAT_ADDR = 1,
OFF_DAT_FCT = 5,
OFF_DAT_SEQNO = 6,
OFF_DAT_OPTS = 8,
};
enum { MAX_LEN_PAYLOAD = MAX_LEN_FRAME-(int)OFF_DAT_OPTS-4 };
enum {
// Bitfields in frame format octet
HDR_FTYPE = 0xE0,
HDR_RFU = 0x1C,
HDR_MAJOR = 0x03
};
enum { HDR_FTYPE_DNFLAG = 0x20 }; // flags DN frame except for HDR_FTYPE_PROP
enum {
// Values of frame type bit field
HDR_FTYPE_JREQ = 0x00,
HDR_FTYPE_JACC = 0x20,
HDR_FTYPE_DAUP = 0x40, // data (unconfirmed) up
HDR_FTYPE_DADN = 0x60, // data (unconfirmed) dn
HDR_FTYPE_DCUP = 0x80, // data confirmed up
HDR_FTYPE_DCDN = 0xA0, // data confirmed dn
HDR_FTYPE_REJOIN = 0xC0, // rejoin for roaming
HDR_FTYPE_PROP = 0xE0
};
enum {
HDR_MAJOR_V1 = 0x00,
};
enum {
// Bitfields in frame control octet
FCT_ADREN = 0x80,
FCT_ADRARQ = 0x40,
FCT_ACK = 0x20,
FCT_MORE = 0x10, // also in DN direction: Class B indicator
FCT_OPTLEN = 0x0F,
};
enum {
// In UP direction: signals class B enabled
FCT_CLASSB = FCT_MORE
};
enum {
NWKID_MASK = (int)0xFE000000,
NWKID_BITS = 7
};
// MAC uplink commands downwlink too
enum {
// Class A
MCMD_LCHK_REQ = 0x02, // - link check request : -
MCMD_LADR_ANS = 0x03, // - link ADR answer : u1:7-3:RFU, 3/2/1: pow/DR/Ch ACK
MCMD_DCAP_ANS = 0x04, // - duty cycle answer : -
MCMD_DN2P_ANS = 0x05, // - 2nd DN slot status : u1:7-2:RFU 1/0:datarate/channel ack
MCMD_DEVS_ANS = 0x06, // - device status ans : u1:battery 0,1-254,255=?, u1:7-6:RFU,5-0:margin(-32..31)
MCMD_SNCH_ANS = 0x07, // - set new channel : u1: 7-2=RFU, 1/0:DR/freq ACK
// Class B
MCMD_PING_IND = 0x10, // - pingability indic : u1: 7=RFU, 6-4:interval, 3-0:datarate
MCMD_PING_ANS = 0x11, // - ack ping freq : u1: 7-1:RFU, 0:freq ok
MCMD_BCNI_REQ = 0x12, // - next beacon start : -
};
// MAC downlink commands
enum {
// Class A
MCMD_LCHK_ANS = 0x02, // link check answer : u1:margin 0-254,255=unknown margin / u1:gwcnt
MCMD_LADR_REQ = 0x03, // link ADR request : u1:DR/TXPow, u2:chmask, u1:chpage/repeat
MCMD_DCAP_REQ = 0x04, // duty cycle cap : u1:255 dead [7-4]:RFU, [3-0]:cap 2^-k
MCMD_DN2P_SET = 0x05, // 2nd DN window param: u1:7-4:RFU/3-0:datarate, u3:freq
MCMD_DEVS_REQ = 0x06, // device status req : -
MCMD_SNCH_REQ = 0x07, // set new channel : u1:chidx, u3:freq, u1:DRrange
// Class B
MCMD_PING_SET = 0x11, // set ping freq : u3: freq
MCMD_BCNI_ANS = 0x12, // next beacon start : u2: delay(in TUNIT millis), u1:channel
};
enum {
MCMD_BCNI_TUNIT = 30 // time unit of delay value in millis
};
enum {
MCMD_LADR_ANS_RFU = 0xF8, // RFU bits
MCMD_LADR_ANS_POWACK = 0x04, // 0=not supported power level
MCMD_LADR_ANS_DRACK = 0x02, // 0=unknown data rate
MCMD_LADR_ANS_CHACK = 0x01, // 0=unknown channel enabled
};
enum {
MCMD_DN2P_ANS_RFU = 0xFC, // RFU bits
MCMD_DN2P_ANS_DRACK = 0x02, // 0=unknown data rate
MCMD_DN2P_ANS_CHACK = 0x01, // 0=unknown channel enabled
};
enum {
MCMD_SNCH_ANS_RFU = 0xFC, // RFU bits
MCMD_SNCH_ANS_DRACK = 0x02, // 0=unknown data rate
MCMD_SNCH_ANS_FQACK = 0x01, // 0=rejected channel frequency
};
enum {
MCMD_PING_ANS_RFU = 0xFE,
MCMD_PING_ANS_FQACK = 0x01
};
enum {
MCMD_DEVS_EXT_POWER = 0x00, // external power supply
MCMD_DEVS_BATT_MIN = 0x01, // min battery value
MCMD_DEVS_BATT_MAX = 0xFE, // max battery value
MCMD_DEVS_BATT_NOINFO = 0xFF, // unknown battery level
};
// Bit fields byte#3 of MCMD_LADR_REQ payload
enum {
MCMD_LADR_CHP_125ON = 0x60, // special channel page enable, bits applied to 64..71
MCMD_LADR_CHP_125OFF = 0x70, // ditto
MCMD_LADR_N3RFU_MASK = 0x80,
MCMD_LADR_CHPAGE_MASK = 0xF0,
MCMD_LADR_REPEAT_MASK = 0x0F,
MCMD_LADR_REPEAT_1 = 0x01,
MCMD_LADR_CHPAGE_1 = 0x10
};
// Bit fields byte#0 of MCMD_LADR_REQ payload
enum {
MCMD_LADR_DR_MASK = 0xF0,
MCMD_LADR_POW_MASK = 0x0F,
MCMD_LADR_DR_SHIFT = 4,
MCMD_LADR_POW_SHIFT = 0,
#if defined(CFG_eu868)
MCMD_LADR_SF12 = DR_SF12<<4,
MCMD_LADR_SF11 = DR_SF11<<4,
MCMD_LADR_SF10 = DR_SF10<<4,
MCMD_LADR_SF9 = DR_SF9 <<4,
MCMD_LADR_SF8 = DR_SF8 <<4,
MCMD_LADR_SF7 = DR_SF7 <<4,
MCMD_LADR_SF7B = DR_SF7B<<4,
MCMD_LADR_FSK = DR_FSK <<4,
MCMD_LADR_20dBm = 0,
MCMD_LADR_14dBm = 1,
MCMD_LADR_11dBm = 2,
MCMD_LADR_8dBm = 3,
MCMD_LADR_5dBm = 4,
MCMD_LADR_2dBm = 5,
#elif defined(CFG_us915)
MCMD_LADR_SF10 = DR_SF10<<4,
MCMD_LADR_SF9 = DR_SF9 <<4,
MCMD_LADR_SF8 = DR_SF8 <<4,
MCMD_LADR_SF7 = DR_SF7 <<4,
MCMD_LADR_SF8C = DR_SF8C<<4,
MCMD_LADR_SF12CR = DR_SF12CR<<4,
MCMD_LADR_SF11CR = DR_SF11CR<<4,
MCMD_LADR_SF10CR = DR_SF10CR<<4,
MCMD_LADR_SF9CR = DR_SF9CR<<4,
MCMD_LADR_SF8CR = DR_SF8CR<<4,
MCMD_LADR_SF7CR = DR_SF7CR<<4,
MCMD_LADR_30dBm = 0,
MCMD_LADR_28dBm = 1,
MCMD_LADR_26dBm = 2,
MCMD_LADR_24dBm = 3,
MCMD_LADR_22dBm = 4,
MCMD_LADR_20dBm = 5,
MCMD_LADR_18dBm = 6,
MCMD_LADR_16dBm = 7,
MCMD_LADR_14dBm = 8,
MCMD_LADR_12dBm = 9,
MCMD_LADR_10dBm = 10
#endif
};
// Device address
typedef u4_t devaddr_t;
// RX quality (device)
enum { RSSI_OFF=64, SNR_SCALEUP=4 };
inline sf_t getSf (rps_t params) { return (sf_t)(params & 0x7); }
inline rps_t setSf (rps_t params, sf_t sf) { return (rps_t)((params & ~0x7) | sf); }
inline bw_t getBw (rps_t params) { return (bw_t)((params >> 3) & 0x3); }
inline rps_t setBw (rps_t params, bw_t cr) { return (rps_t)((params & ~0x18) | (cr<<3)); }
inline cr_t getCr (rps_t params) { return (cr_t)((params >> 5) & 0x3); }
inline rps_t setCr (rps_t params, cr_t cr) { return (rps_t)((params & ~0x60) | (cr<<5)); }
inline int getNocrc(rps_t params) { return ((params >> 7) & 0x1); }
inline rps_t setNocrc(rps_t params, int nocrc) { return (rps_t)((params & ~0x80) | (nocrc<<7)); }
inline int getIh (rps_t params) { return ((params >> 8) & 0xFF); }
inline rps_t setIh (rps_t params, int ih) { return (rps_t)((params & ~0xFF00) | (ih<<8)); }
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);
}
#define MAKERPS(sf,bw,cr,ih,nocrc) ((rps_t)((sf) | ((bw)<<3) | ((cr)<<5) | ((nocrc)?(1<<7):0) | ((ih&0xFF)<<8)))
// Two frames with params r1/r2 would interfere on air: same SFx + BWx
inline int sameSfBw(rps_t r1, rps_t r2) { return ((r1^r2)&0x1F) == 0; }
extern const u1_t _DR2RPS_CRC[];
inline rps_t updr2rps (dr_t dr) { return (rps_t)_DR2RPS_CRC[dr+1]; }
inline rps_t dndr2rps (dr_t dr) { return setNocrc(updr2rps(dr),1); }
inline int isFasterDR (dr_t dr1, dr_t dr2) { return dr1 > dr2; }
inline int isSlowerDR (dr_t dr1, dr_t dr2) { return dr1 < dr2; }
inline dr_t incDR (dr_t dr) { return _DR2RPS_CRC[dr+2]==ILLEGAL_RPS ? dr : (dr_t)(dr+1); } // increase data rate
inline dr_t decDR (dr_t dr) { return _DR2RPS_CRC[dr ]==ILLEGAL_RPS ? dr : (dr_t)(dr-1); } // decrease data rate
inline dr_t assertDR (dr_t dr) { return _DR2RPS_CRC[dr+1]==ILLEGAL_RPS ? DR_DFLTMIN : dr; } // force into a valid DR
inline bit_t validDR (dr_t dr) { return _DR2RPS_CRC[dr+1]!=ILLEGAL_RPS; } // in range
inline dr_t lowerDR (dr_t dr, u1_t n) { while(n--){dr=decDR(dr);} return dr; } // decrease data rate by n steps
//
// BEG: Keep in sync with lorabase.hpp
// ================================================================================
// Convert between dBm values and power codes (MCMD_LADR_XdBm)
s1_t pow2dBm (u1_t mcmd_ladr_p1);
// Calculate airtime
ostime_t calcAirTime (rps_t rps, u1_t plen);
// Sensitivity at given SF/BW
int getSensitivity (rps_t rps);
#endif // _lorabase_h_

88
include/main.h Normal file
View File

@ -0,0 +1,88 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l0xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
TIM_HandleTypeDef htim2;
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define LED_Pin GPIO_PIN_1
#define LED_GPIO_Port GPIOA
#define NSS_Pin GPIO_PIN_4
#define NSS_GPIO_Port GPIOA
#define RST_Pin GPIO_PIN_9
#define RST_GPIO_Port GPIOA
#define DIO0_Pin GPIO_PIN_10
#define DIO0_GPIO_Port GPIOA
#define DIO0_EXTI_IRQn EXTI4_15_IRQn
#define DIO1_Pin GPIO_PIN_4
#define DIO1_GPIO_Port GPIOB
#define DIO1_EXTI_IRQn EXTI4_15_IRQn
#define DIO2_Pin GPIO_PIN_5
#define DIO2_GPIO_Port GPIOB
#define DIO2_EXTI_IRQn EXTI4_15_IRQn
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */

232
include/oslmic.h Normal file
View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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
#ifndef _oslmic_h_
#define _oslmic_h_
// Dependencies required for the LoRa MAC in C to run.
// These settings can be adapted to the underlying system.
// You should not, however, change the lmic.[hc]
//================================================================================
//================================================================================
// Target platform as C library
typedef unsigned char bit_t;
typedef unsigned char u1_t;
typedef signed char s1_t;
typedef unsigned short u2_t;
typedef short s2_t;
typedef unsigned int u4_t;
typedef int s4_t;
typedef unsigned long long u8_t;
typedef long long s8_t;
typedef unsigned int uint;
typedef const char* str_t;
#include <string.h>
#include "hal.h"
#define EV(a,b,c) /**/
#define DO_DEVDB(field1,field2) /**/
#if !defined(CFG_noassert)
#define ASSERT(cond) if(!(cond)) hal_failed()
#else
#define ASSERT(cond) /**/
#endif
#define os_clearMem(a,b) memset(a,0,b)
#define os_copyMem(a,b,c) memcpy(a,b,c)
typedef struct osjob_t osjob_t;
typedef struct band_t band_t;
typedef struct chnldef_t chnldef_t;
typedef struct rxsched_t rxsched_t;
typedef struct bcninfo_t bcninfo_t;
typedef const u1_t* xref2cu1_t;
typedef u1_t* xref2u1_t;
#define TYPEDEF_xref2rps_t typedef rps_t* xref2rps_t
#define TYPEDEF_xref2rxsched_t typedef rxsched_t* xref2rxsched_t
#define TYPEDEF_xref2chnldef_t typedef chnldef_t* xref2chnldef_t
#define TYPEDEF_xref2band_t typedef band_t* xref2band_t
#define TYPEDEF_xref2osjob_t typedef osjob_t* xref2osjob_t
#define SIZEOFEXPR(x) sizeof(x)
#define ON_LMIC_EVENT(ev) onEvent(ev)
#define DECL_ON_LMIC_EVENT void onEvent(ev_t e)
extern u4_t AESAUX[];
extern u4_t AESKEY[];
#define AESkey ((u1_t*)AESKEY)
#define AESaux ((u1_t*)AESAUX)
#define FUNC_ADDR(func) (&(func))
u1_t radio_rand1 (void);
#define os_getRndU1() radio_rand1()
#define DEFINE_LMIC struct lmic_t LMIC
#define DECLARE_LMIC extern struct lmic_t LMIC
void radio_init (void);
void radio_irq_handler (u1_t dio);
void os_init (void);
void os_runloop (void);
//================================================================================
#ifndef RX_RAMPUP
#define RX_RAMPUP (us2osticks(2000))
#endif
#ifndef TX_RAMPUP
#define TX_RAMPUP (us2osticks(2000))
#endif
#ifndef OSTICKS_PER_SEC
#define OSTICKS_PER_SEC 32000
#elif OSTICKS_PER_SEC < 10000 || OSTICKS_PER_SEC > 64516
#error Illegal OSTICKS_PER_SEC - must be in range [10000:64516]. One tick must be 15.5us .. 100us long.
#endif
typedef s4_t ostime_t;
#if !HAS_ostick_conv
#define us2osticks(us) ((ostime_t)( ((s8_t)(us) * OSTICKS_PER_SEC) / 1000000))
#define ms2osticks(ms) ((ostime_t)( ((s8_t)(ms) * OSTICKS_PER_SEC) / 1000))
#define sec2osticks(sec) ((ostime_t)( (s8_t)(sec) * OSTICKS_PER_SEC))
#define osticks2ms(os) ((s4_t)(((os)*(s8_t)1000 ) / OSTICKS_PER_SEC))
#define osticks2us(os) ((s4_t)(((os)*(s8_t)1000000 ) / OSTICKS_PER_SEC))
// Special versions
#define us2osticksCeil(us) ((ostime_t)( ((s8_t)(us) * OSTICKS_PER_SEC + 999999) / 1000000))
#define us2osticksRound(us) ((ostime_t)( ((s8_t)(us) * OSTICKS_PER_SEC + 500000) / 1000000))
#define ms2osticksCeil(ms) ((ostime_t)( ((s8_t)(ms) * OSTICKS_PER_SEC + 999) / 1000))
#define ms2osticksRound(ms) ((ostime_t)( ((s8_t)(ms) * OSTICKS_PER_SEC + 500) / 1000))
#endif
struct osjob_t; // fwd decl.
typedef void (*osjobcb_t) (struct osjob_t*);
struct osjob_t {
struct osjob_t* next;
ostime_t deadline;
osjobcb_t func;
};
TYPEDEF_xref2osjob_t;
#ifndef HAS_os_calls
#ifndef os_getDevKey
void os_getDevKey (xref2u1_t buf);
#endif
#ifndef os_getArtEui
void os_getArtEui (xref2u1_t buf);
#endif
#ifndef os_getDevEui
void os_getDevEui (xref2u1_t buf);
#endif
#ifndef os_setCallback
void os_setCallback (xref2osjob_t job, osjobcb_t cb);
#endif
#ifndef os_setTimedCallback
void os_setTimedCallback (xref2osjob_t job, ostime_t time, osjobcb_t cb);
#endif
#ifndef os_clearCallback
void os_clearCallback (xref2osjob_t job);
#endif
#ifndef os_getTime
ostime_t os_getTime (void);
#endif
#ifndef os_getTimeSecs
uint os_getTimeSecs (void);
#endif
#ifndef os_radio
void os_radio (u1_t mode);
#endif
#ifndef os_getBattLevel
u1_t os_getBattLevel (void);
#endif
#ifndef os_rlsbf4
//! Read 32-bit quantity from given pointer in little endian byte order.
u4_t os_rlsbf4 (xref2cu1_t buf);
#endif
#ifndef os_wlsbf4
//! Write 32-bit quntity into buffer in little endian byte order.
void os_wlsbf4 (xref2u1_t buf, u4_t value);
#endif
#ifndef os_rmsbf4
//! Read 32-bit quantity from given pointer in big endian byte order.
u4_t os_rmsbf4 (xref2cu1_t buf);
#endif
#ifndef os_wmsbf4
//! Write 32-bit quntity into buffer in big endian byte order.
void os_wmsbf4 (xref2u1_t buf, u4_t value);
#endif
#ifndef os_rlsbf2
//! Read 16-bit quantity from given pointer in little endian byte order.
u2_t os_rlsbf2 (xref2cu1_t buf);
#endif
#ifndef os_wlsbf2
//! Write 16-bit quntity into buffer in little endian byte order.
void os_wlsbf2 (xref2u1_t buf, u2_t value);
#endif
//! Get random number (default impl for u2_t).
#ifndef os_getRndU2
#define os_getRndU2() ((u2_t)((os_getRndU1()<<8)|os_getRndU1()))
#endif
#ifndef os_crc16
u2_t os_crc16 (xref2u1_t d, uint len);
#endif
#endif // !HAS_os_calls
// ======================================================================
// AES support
// !!Keep in sync with lorabase.hpp!!
#ifndef AES_ENC // if AES_ENC is defined as macro all other values must be too
#define AES_ENC 0x00
#define AES_DEC 0x01
#define AES_MIC 0x02
#define AES_CTR 0x04
#define AES_MICNOAUX 0x08
#endif
#ifndef AESkey // if AESkey is defined as macro all other values must be too
extern xref2u1_t AESkey;
extern xref2u1_t AESaux;
#endif
#ifndef os_aes
u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len);
#endif
#endif // _oslmic_h_

37
include/secconfig.h Normal file
View File

@ -0,0 +1,37 @@
/*
secconfig.h
configuration file with security information, not shared on the internet.
THIS IS AN EXAMPLE FILE, PLEASE RENAME TO secconfig.h
*/
#include "oslmic.h"
// When Using OTAA as activation type (default)
// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t APPEUI[8]={ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45 };
// This should also be in little endian format, see above.
static const u1_t DEVEUI[8]={ 0xD6, 0x33, 0x06, 0xD0, 0x7E, 0xD5, 0xB3, 0x70 };
// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t APPKEY[16] = { 0x44, 0x99, 0xB4, 0xD3, 0xDB, 0x02, 0x07, 0xE3, 0xD6, 0x1A, 0x06, 0x6E, 0xCB, 0x26, 0xFC, 0xA2 };
// When using ABP as activation type
// set DISABLE_JOIN in config.h in the lmic library
// LoRaWAN NwkSKey, network session key (TTN msb first)
static const u1_t NWKSKEY[16] = { 0xE0, 0x92, 0xEA, 0x35, 0x7C, 0x80, 0xA8, 0x26, 0xAE, 0xB0, 0x7C, 0xF3, 0xD7, 0xCA, 0xAD, 0x85 };
// LoRaWAN AppSKey, application session key (TTN msn first)
static const u1_t APPSKEY[16] = { 0xB2, 0xB5, 0xC8, 0xDF, 0x37, 0x3F, 0xFF, 0x37, 0x39, 0x86, 0xAD, 0x48, 0x51, 0x96, 0xDD, 0x01 };
// LoRaWAN DevAddr, end-device address (TTN msb first)
static const u4_t DEVADDR = 0x260B5215 ;

View File

@ -0,0 +1,329 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32l0xx_hal_conf.h
* @author MCD Application Team
* @brief HAL configuration template file.
* This file should be copied to the application folder and renamed
* to stm32l0xx_hal_conf.h.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32L0xx_HAL_CONF_H
#define __STM32L0xx_HAL_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
*/
#define HAL_MODULE_ENABLED
/*#define HAL_ADC_MODULE_ENABLED */
/*#define HAL_CRYP_MODULE_ENABLED */
/*#define HAL_COMP_MODULE_ENABLED */
/*#define HAL_CRC_MODULE_ENABLED */
/*#define HAL_CRYP_MODULE_ENABLED */
/*#define HAL_DAC_MODULE_ENABLED */
/*#define HAL_FIREWALL_MODULE_ENABLED */
/*#define HAL_I2S_MODULE_ENABLED */
/*#define HAL_IWDG_MODULE_ENABLED */
/*#define HAL_LCD_MODULE_ENABLED */
/*#define HAL_LPTIM_MODULE_ENABLED */
/*#define HAL_RNG_MODULE_ENABLED */
/*#define HAL_RTC_MODULE_ENABLED */
#define HAL_SPI_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
/*#define HAL_TSC_MODULE_ENABLED */
#define HAL_UART_MODULE_ENABLED
/*#define HAL_USART_MODULE_ENABLED */
/*#define HAL_IRDA_MODULE_ENABLED */
/*#define HAL_SMARTCARD_MODULE_ENABLED */
/*#define HAL_SMBUS_MODULE_ENABLED */
/*#define HAL_WWDG_MODULE_ENABLED */
/*#define HAL_PCD_MODULE_ENABLED */
#define HAL_GPIO_MODULE_ENABLED
#define HAL_EXTI_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
/* ########################## Oscillator Values adaptation ####################*/
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief Internal Multiple Speed oscillator (MSI) default value.
* This value is the default MSI range value after Reset.
*/
#if !defined (MSI_VALUE)
#define MSI_VALUE ((uint32_t)2097000U) /*!< Value of the Internal oscillator in Hz*/
#endif /* MSI_VALUE */
/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSI is used as system clock source, directly or through the PLL).
*/
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @brief Internal High Speed oscillator for USB (HSI48) value.
*/
#if !defined (HSI48_VALUE)
#define HSI48_VALUE ((uint32_t)48000000U) /*!< Value of the Internal High Speed oscillator for USB in Hz.
The real value may vary depending on the variations
in voltage and temperature. */
#endif /* HSI48_VALUE */
/**
* @brief Internal Low Speed oscillator (LSI) value.
*/
#if !defined (LSI_VALUE)
#define LSI_VALUE ((uint32_t)37000U) /*!< LSI Typical Value in Hz*/
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature.*/
/**
* @brief External Low Speed oscillator (LSE) value.
* This value is used by the UART, RTC HAL module to compute the system frequency
*/
#if !defined (LSE_VALUE)
#define LSE_VALUE ((uint32_t)32768U) /*!< Value of the External oscillator in Hz*/
#endif /* LSE_VALUE */
#if !defined (LSE_STARTUP_TIMEOUT)
#define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */
#endif /* LSE_STARTUP_TIMEOUT */
/* Tip: To avoid modifying this file each time you need to use different HSE,
=== you can define the HSE value in your toolchain compiler preprocessor. */
/* ########################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY ((uint32_t)3U) /*!< tick interrupt priority */
#define USE_RTOS 0U
#define PREFETCH_ENABLE 0U
#define PREREAD_ENABLE 1U
#define BUFFER_CACHE_DISABLE 0U
/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */
/* ################## Register callback feature configuration ############### */
/**
* @brief Set below the peripheral configuration to "1U" to add the support
* of HAL callback registration/deregistration feature for the HAL
* driver(s). This allows user application to provide specific callback
* functions thanks to HAL_PPP_RegisterCallback() rather than overwriting
* the default weak callback functions (see each stm32l0xx_hal_ppp.h file
* for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef
* for each PPP peripheral).
*/
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U
#define USE_HAL_COMP_REGISTER_CALLBACKS 0U
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U
#define USE_HAL_TSC_REGISTER_CALLBACKS 0U
#define USE_HAL_UART_REGISTER_CALLBACKS 0U
#define USE_HAL_USART_REGISTER_CALLBACKS 0U
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U
/* Includes ------------------------------------------------------------------*/
/**
* @brief Include module's header file
*/
#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32l0xx_hal_rcc.h"
#endif /* HAL_RCC_MODULE_ENABLED */
#ifdef HAL_EXTI_MODULE_ENABLED
#include "stm32l0xx_hal_exti.h"
#endif /* HAL_EXTI_MODULE_ENABLED */
#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm32l0xx_hal_gpio.h"
#endif /* HAL_GPIO_MODULE_ENABLED */
#ifdef HAL_DMA_MODULE_ENABLED
#include "stm32l0xx_hal_dma.h"
#endif /* HAL_DMA_MODULE_ENABLED */
#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32l0xx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */
#ifdef HAL_ADC_MODULE_ENABLED
#include "stm32l0xx_hal_adc.h"
#endif /* HAL_ADC_MODULE_ENABLED */
#ifdef HAL_COMP_MODULE_ENABLED
#include "stm32l0xx_hal_comp.h"
#endif /* HAL_COMP_MODULE_ENABLED */
#ifdef HAL_CRC_MODULE_ENABLED
#include "stm32l0xx_hal_crc.h"
#endif /* HAL_CRC_MODULE_ENABLED */
#ifdef HAL_CRYP_MODULE_ENABLED
#include "stm32l0xx_hal_cryp.h"
#endif /* HAL_CRYP_MODULE_ENABLED */
#ifdef HAL_DAC_MODULE_ENABLED
#include "stm32l0xx_hal_dac.h"
#endif /* HAL_DAC_MODULE_ENABLED */
#ifdef HAL_FIREWALL_MODULE_ENABLED
#include "stm32l0xx_hal_firewall.h"
#endif /* HAL_FIREWALL_MODULE_ENABLED */
#ifdef HAL_FLASH_MODULE_ENABLED
#include "stm32l0xx_hal_flash.h"
#endif /* HAL_FLASH_MODULE_ENABLED */
#ifdef HAL_I2C_MODULE_ENABLED
#include "stm32l0xx_hal_i2c.h"
#endif /* HAL_I2C_MODULE_ENABLED */
#ifdef HAL_I2S_MODULE_ENABLED
#include "stm32l0xx_hal_i2s.h"
#endif /* HAL_I2S_MODULE_ENABLED */
#ifdef HAL_IWDG_MODULE_ENABLED
#include "stm32l0xx_hal_iwdg.h"
#endif /* HAL_IWDG_MODULE_ENABLED */
#ifdef HAL_LCD_MODULE_ENABLED
#include "stm32l0xx_hal_lcd.h"
#endif /* HAL_LCD_MODULE_ENABLED */
#ifdef HAL_LPTIM_MODULE_ENABLED
#include "stm32l0xx_hal_lptim.h"
#endif /* HAL_LPTIM_MODULE_ENABLED */
#ifdef HAL_PWR_MODULE_ENABLED
#include "stm32l0xx_hal_pwr.h"
#endif /* HAL_PWR_MODULE_ENABLED */
#ifdef HAL_RNG_MODULE_ENABLED
#include "stm32l0xx_hal_rng.h"
#endif /* HAL_RNG_MODULE_ENABLED */
#ifdef HAL_RTC_MODULE_ENABLED
#include "stm32l0xx_hal_rtc.h"
#endif /* HAL_RTC_MODULE_ENABLED */
#ifdef HAL_SPI_MODULE_ENABLED
#include "stm32l0xx_hal_spi.h"
#endif /* HAL_SPI_MODULE_ENABLED */
#ifdef HAL_TIM_MODULE_ENABLED
#include "stm32l0xx_hal_tim.h"
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef HAL_TSC_MODULE_ENABLED
#include "stm32l0xx_hal_tsc.h"
#endif /* HAL_TSC_MODULE_ENABLED */
#ifdef HAL_UART_MODULE_ENABLED
#include "stm32l0xx_hal_uart.h"
#endif /* HAL_UART_MODULE_ENABLED */
#ifdef HAL_USART_MODULE_ENABLED
#include "stm32l0xx_hal_usart.h"
#endif /* HAL_USART_MODULE_ENABLED */
#ifdef HAL_IRDA_MODULE_ENABLED
#include "stm32l0xx_hal_irda.h"
#endif /* HAL_IRDA_MODULE_ENABLED */
#ifdef HAL_SMARTCARD_MODULE_ENABLED
#include "stm32l0xx_hal_smartcard.h"
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
#ifdef HAL_SMBUS_MODULE_ENABLED
#include "stm32l0xx_hal_smbus.h"
#endif /* HAL_SMBUS_MODULE_ENABLED */
#ifdef HAL_WWDG_MODULE_ENABLED
#include "stm32l0xx_hal_wwdg.h"
#endif /* HAL_WWDG_MODULE_ENABLED */
#ifdef HAL_PCD_MODULE_ENABLED
#include "stm32l0xx_hal_pcd.h"
#endif /* HAL_PCD_MODULE_ENABLED */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
#ifdef __cplusplus
}
#endif
#endif /* __STM32L0xx_HAL_CONF_H */

64
include/stm32l0xx_it.h Normal file
View File

@ -0,0 +1,64 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32l0xx_it.h
* @brief This file contains the headers of the interrupt handlers.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32L0xx_IT_H
#define __STM32L0xx_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void NMI_Handler(void);
void HardFault_Handler(void);
void SVC_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void EXTI4_15_IRQHandler(void);
void TIM2_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* __STM32L0xx_IT_H */

46
lib/README Executable file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

23
platformio.ini Executable file
View File

@ -0,0 +1,23 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:minipill_l051c8_lora_stm32cube]
platform = ststm32
board = minipill_l051c8_lora_stm32cube
framework = stm32cube
board_build.stm32cube.startup_file = startup_stm32l051xx.s
build_flags=
-D CFG_eu868
-D CFG_sx1276_radio
-D DISABLE_JOIN
upload_protocol=custom
upload_command = st-flash write $SOURCE 0x8000000
debug_tool=stlink
monitor_port=/dev/ttyUSB0

383
src/aes.c Normal file
View File

@ -0,0 +1,383 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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.
*/
#include "oslmic.h"
#define AES_MICSUB 0x30 // internal use only
static const u4_t AES_RCON[10] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000
};
static const u1_t AES_S[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
};
static const u4_t AES_E1[256] = {
0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554,
0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A,
0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B,
0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B,
0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F,
0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F,
0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5,
0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F,
0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB,
0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497,
0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED,
0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A,
0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594,
0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3,
0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504,
0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D,
0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739,
0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395,
0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883,
0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76,
0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4,
0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B,
0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0,
0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818,
0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651,
0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85,
0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12,
0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9,
0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7,
0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A,
0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8,
0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A,
};
static const u4_t AES_E2[256] = {
0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5,
0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676,
0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0,
0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0,
0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC,
0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515,
0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A,
0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575,
0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0,
0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484,
0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B,
0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF,
0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585,
0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8,
0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5,
0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2,
0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717,
0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373,
0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888,
0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB,
0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C,
0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979,
0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9,
0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808,
0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6,
0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A,
0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E,
0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E,
0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494,
0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF,
0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868,
0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616,
};
static const u4_t AES_E3[256] = {
0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5,
0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76,
0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0,
0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0,
0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC,
0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15,
0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A,
0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75,
0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0,
0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384,
0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B,
0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF,
0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185,
0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8,
0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5,
0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2,
0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17,
0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673,
0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88,
0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB,
0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C,
0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279,
0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9,
0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008,
0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6,
0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A,
0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E,
0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E,
0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394,
0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF,
0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068,
0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16,
};
static const u4_t AES_E4[256] = {
0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C,
};
#define msbf4_read(p) ((p)[0]<<24 | (p)[1]<<16 | (p)[2]<<8 | (p)[3])
#define msbf4_write(p,v) (p)[0]=(v)>>24,(p)[1]=(v)>>16,(p)[2]=(v)>>8,(p)[3]=(v)
#define swapmsbf(x) ( (x&0xFF)<<24 | (x&0xFF00)<<8 | (x&0xFF0000)>>8 | (x>>24) )
#define u1(v) ((u1_t)(v))
#define AES_key4(r1,r2,r3,r0,i) r1 = ki[i+1]; \
r2 = ki[i+2]; \
r3 = ki[i+3]; \
r0 = ki[i]
#define AES_expr4(r1,r2,r3,r0,i) r1 ^= AES_E4[u1(i)]; \
r2 ^= AES_E3[u1(i>>8)]; \
r3 ^= AES_E2[u1(i>>16)]; \
r0 ^= AES_E1[ (i>>24)]
#define AES_expr(a,r0,r1,r2,r3,i) a = ki[i]; \
a ^= (AES_S[ r0>>24 ]<<24); \
a ^= (AES_S[u1(r1>>16)]<<16); \
a ^= (AES_S[u1(r2>> 8)]<< 8); \
a ^= AES_S[u1(r3) ]
// global area for passing parameters (aux, key) and for storing round keys
u4_t AESAUX[16/sizeof(u4_t)];
u4_t AESKEY[11*16/sizeof(u4_t)];
// generate 1+10 roundkeys for encryption with 128-bit key
// read 128-bit key from AESKEY in MSBF, generate roundkey words in place
static void aesroundkeys () {
int i;
u4_t b;
for( i=0; i<4; i++) {
AESKEY[i] = swapmsbf(AESKEY[i]);
}
b = AESKEY[3];
for( ; i<44; i++ ) {
if( i%4==0 ) {
// b = SubWord(RotWord(b)) xor Rcon[i/4]
b = (AES_S[u1(b >> 16)] << 24) ^
(AES_S[u1(b >> 8)] << 16) ^
(AES_S[u1(b) ] << 8) ^
(AES_S[ b >> 24 ] ) ^
AES_RCON[(i-4)/4];
}
AESKEY[i] = b ^= AESKEY[i-4];
}
}
u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) {
aesroundkeys();
if( mode & AES_MICNOAUX ) {
AESAUX[0] = AESAUX[1] = AESAUX[2] = AESAUX[3] = 0;
} else {
AESAUX[0] = swapmsbf(AESAUX[0]);
AESAUX[1] = swapmsbf(AESAUX[1]);
AESAUX[2] = swapmsbf(AESAUX[2]);
AESAUX[3] = swapmsbf(AESAUX[3]);
}
while( (signed char)len > 0 ) {
u4_t a0, a1, a2, a3;
u4_t t0, t1, t2, t3;
u4_t *ki, *ke;
// load input block
if( (mode & AES_CTR) || ((mode & AES_MIC) && (mode & AES_MICNOAUX)==0) ) { // load CTR block or first MIC block
a0 = AESAUX[0];
a1 = AESAUX[1];
a2 = AESAUX[2];
a3 = AESAUX[3];
}
else if( (mode & AES_MIC) && len <= 16 ) { // last MIC block
a0 = a1 = a2 = a3 = 0; // load null block
mode |= ((len == 16) ? 1 : 2) << 4; // set MICSUB: CMAC subkey K1 or K2
} else
LOADDATA: { // load data block (partially)
for(t0=0; t0<16; t0++) {
t1 = (t1<<8) | ((t0<len) ? buf[t0] : (t0==len) ? 0x80 : 0x00);
if((t0&3)==3) {
a0 = a1;
a1 = a2;
a2 = a3;
a3 = t1;
}
}
if( mode & AES_MIC ) {
a0 ^= AESAUX[0];
a1 ^= AESAUX[1];
a2 ^= AESAUX[2];
a3 ^= AESAUX[3];
}
}
// perform AES encryption on block in a0-a3
ki = AESKEY;
ke = ki + 8*4;
a0 ^= ki[0];
a1 ^= ki[1];
a2 ^= ki[2];
a3 ^= ki[3];
do {
AES_key4 (t1,t2,t3,t0,4);
AES_expr4(t1,t2,t3,t0,a0);
AES_expr4(t2,t3,t0,t1,a1);
AES_expr4(t3,t0,t1,t2,a2);
AES_expr4(t0,t1,t2,t3,a3);
AES_key4 (a1,a2,a3,a0,8);
AES_expr4(a1,a2,a3,a0,t0);
AES_expr4(a2,a3,a0,a1,t1);
AES_expr4(a3,a0,a1,a2,t2);
AES_expr4(a0,a1,a2,a3,t3);
} while( (ki+=8) < ke );
AES_key4 (t1,t2,t3,t0,4);
AES_expr4(t1,t2,t3,t0,a0);
AES_expr4(t2,t3,t0,t1,a1);
AES_expr4(t3,t0,t1,t2,a2);
AES_expr4(t0,t1,t2,t3,a3);
AES_expr(a0,t0,t1,t2,t3,8);
AES_expr(a1,t1,t2,t3,t0,9);
AES_expr(a2,t2,t3,t0,t1,10);
AES_expr(a3,t3,t0,t1,t2,11);
// result of AES encryption in a0-a3
if( mode & AES_MIC ) {
if( (t1 = (mode & AES_MICSUB) >> 4) != 0 ) { // last block
do {
// compute CMAC subkey K1 and K2
t0 = a0 >> 31; // save MSB
a0 = (a0 << 1) | (a1 >> 31);
a1 = (a1 << 1) | (a2 >> 31);
a2 = (a2 << 1) | (a3 >> 31);
a3 = (a3 << 1);
if( t0 ) a3 ^= 0x87;
} while( --t1 );
AESAUX[0] ^= a0;
AESAUX[1] ^= a1;
AESAUX[2] ^= a2;
AESAUX[3] ^= a3;
mode &= ~AES_MICSUB;
goto LOADDATA;
} else {
// save cipher block as new iv
AESAUX[0] = a0;
AESAUX[1] = a1;
AESAUX[2] = a2;
AESAUX[3] = a3;
}
} else { // CIPHER
if( mode & AES_CTR ) { // xor block (partially)
t0 = (len > 16) ? 16: len;
for(t1=0; t1<t0; t1++) {
buf[t1] ^= (a0>>24);
a0 <<= 8;
if((t1&3)==3) {
a0 = a1;
a1 = a2;
a2 = a3;
}
}
// update counter
AESAUX[3]++;
} else { // ECB
// store block
msbf4_write(buf+0, a0);
msbf4_write(buf+4, a1);
msbf4_write(buf+8, a2);
msbf4_write(buf+12, a3);
}
}
// update block state
if( (mode & AES_MIC)==0 || (mode & AES_MICNOAUX) ) {
buf += 16;
len -= 16;
}
mode |= AES_MICNOAUX;
}
return AESAUX[0];
}

152
src/debug.c Normal file
View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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.
*/
#include "main.h"
#include "debug.h"
#include "lmic.h"
#define myUART huart1 // <--------- change to your setup
/* ************************************** */
/* DO NOT CHANGE BELOW THIS LINE */
/* ************************************** */
void debug_init () {
// configure LED pin as output
debug_led(0);
// configure USART1 (115200/8N1, tx-only)
// print banner
debug_str("\r\n============== DEBUG STARTED ==============\r\n");
}
void debug_led (int val) {
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,val);
}
void debug_char (char c) {
char buffer[] = "";
buffer[0]= c;
HAL_UART_Transmit(&myUART,(uint8_t*)buffer,sizeof(buffer),HAL_MAX_DELAY);
}
void debug_hex (u1_t b) {
debug_char("0123456789ABCDEF"[b>>4]);
debug_char("0123456789ABCDEF"[b&0xF]);
}
void debug_buf (const u1_t* buf, int len) {
while(len--) {
debug_hex(*buf++);
debug_char(' ');
}
debug_char('\r');
debug_char('\n');
}
void debug_uint (u4_t v) {
for(s1_t n=24; n>=0; n-=8) {
debug_hex(v>>n);
}
}
void debug_int (s4_t v) {
char buf[10], *p = buf;
int n = debug_fmt(buf, sizeof(buf), v, 10, 0, 0);
while(n--)
debug_char(*p++);
}
void debug_str (const char* str) {
while(*str) {
debug_char(*str++);
}
}
void debug_val (const char* label, u4_t val) {
debug_str(label);
debug_uint(val);
debug_char('\r');
debug_char('\n');
}
void debug_valdec (const char* label, s4_t val) {
debug_str(label);
debug_int(val);
debug_char('\r');
debug_char('\n');
}
int debug_fmt (char* buf, int max, s4_t val, int base, int width, char pad) {
char num[33], *p = num, *b = buf;
u4_t m, v;
// special handling of negative decimals
v = (base == 10 && val < 0) ? -val : val;
// generate digits backwards
do {
*p++ = ((m=v%base) <= 9) ? m+'0' : m+'A'-10;
} while( v /= base );
// prefix negative decimals with '-'
if(base == 10 && val < 0) {
*p++ = '-';
}
// add leading zeroes or spaces
while( b-buf < max-1 && b-buf < width-(p-num) ) {
*b++ = pad;
}
// copy digits and sign forwards
do *b++ = *--p;
while( b-buf < max && p > num );
// return number of characters written
return b - buf;
}
void debug_event (int ev) {
static const char* evnames[] = {
[EV_SCAN_TIMEOUT] = "SCAN_TIMEOUT",
[EV_BEACON_FOUND] = "BEACON_FOUND",
[EV_BEACON_MISSED] = "BEACON_MISSED",
[EV_BEACON_TRACKED] = "BEACON_TRACKED",
[EV_JOINING] = "JOINING",
[EV_JOINED] = "JOINED",
[EV_RFU1] = "RFU1",
[EV_JOIN_FAILED] = "JOIN_FAILED",
[EV_REJOIN_FAILED] = "REJOIN_FAILED",
[EV_TXCOMPLETE] = "TXCOMPLETE",
[EV_LOST_TSYNC] = "LOST_TSYNC",
[EV_RESET] = "RESET",
[EV_RXCOMPLETE] = "RXCOMPLETE",
[EV_LINK_DEAD] = "LINK_DEAD",
[EV_LINK_ALIVE] = "LINK_ALIVE",
[EV_SCAN_FOUND] = "SCAN_FOUND",
[EV_TXSTART] = "EV_TXSTART",
};
debug_str((ev < sizeof(evnames)/sizeof(evnames[0])) ? evnames[ev] : "EV_UNKNOWN" );
debug_char('\r');
debug_char('\n');
}

228
src/hal.c Normal file
View File

@ -0,0 +1,228 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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.
*/
/*
* This file is a futher development from the great IBM LMIC
* made by Hjalmar SkovHolm Hansen
* Denmark
*/
#include "lmic.h"
#include "main.h"
#define myTIMER htim2 // <--------- change to your setup
#define mySPI hspi1 // <--------- change to your setup
/* ************************************** */
/* DO NOT CHANGE BELOW THIS LINE */
/* ************************************** */
// HAL state
static struct {
int irqlevel;
u4_t ticks;
} HAL;
// -----------------------------------------------------------------------------
// I/O
static void hal_io_init () {
//already done by cubemx
}
// val ==1 => tx 1, rx 0 ; val == 0 => tx 0, rx 1
void hal_pin_rxtx (u1_t val) {
#ifdef RX_GPIO_Port
#ifdef TX_GPIO_Port
HAL_GPIO_WritePin(RX_GPIO_Port,RX_Pin,~val);
HAL_GPIO_WritePin(TX_GPIO_Port,TX_Pin,val);
#endif
#endif
}
// set radio NSS pin to given value
void hal_pin_nss (u1_t val) {
HAL_GPIO_WritePin(NSS_GPIO_Port,NSS_Pin,val);
}
// set radio RST pin to given value (or keep floating!)
void hal_pin_rst (u1_t val) {
if(val == 0 || val == 1) { // drive pin
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = RST_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(RST_GPIO_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(RST_GPIO_Port,RST_Pin,val);
} else { // keep pin floating
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = RST_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(RST_GPIO_Port, &GPIO_InitStruct);
}
}
extern void radio_irq_handler(u1_t dio);
// generic EXTI IRQ handler for all channels
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin_int){
// DIO 0
if(GPIO_Pin_int == DIO0_Pin) {
// invoke radio handler (on IRQ!)
radio_irq_handler(0);
}
// DIO 1
if(GPIO_Pin_int == DIO1_Pin) {
// invoke radio handler (on IRQ!)
radio_irq_handler(1);
}
// DIO 2
if(GPIO_Pin_int == DIO2_Pin) {
// invoke radio handler (on IRQ!)
radio_irq_handler(2);
}
}
// -----------------------------------------------------------------------------
// SPI
void hal_spi_init () {
// already done by cube mx
}
// perform SPI transaction with radio
u1_t hal_spi (u1_t out) {
char outbuffer[] ="";
char inbuffer[] ="";
outbuffer[0] = out;
HAL_SPI_TransmitReceive(&mySPI,outbuffer,inbuffer,sizeof(outbuffer),HAL_MAX_DELAY);
return inbuffer[0];
}
// -----------------------------------------------------------------------------
// TIME
static void hal_time_init () {
// already done by cubemx
}
u4_t hal_ticks () {
hal_disableIRQs();
u4_t t = HAL.ticks;
u2_t cnt = __HAL_TIM_GET_COUNTER(&myTIMER);
if(__HAL_TIM_GET_FLAG(&myTIMER, TIM_FLAG_CC1) != RESET){
if(__HAL_TIM_GET_IT_SOURCE(&myTIMER, TIM_IT_CC1) !=RESET){
cnt = __HAL_TIM_GET_COUNTER(&myTIMER);
t++;
}
}
hal_enableIRQs();
return (t<<16)|cnt;
}
// return modified delta ticks from now to specified ticktime (0 for past, FFFF for far future)
static u2_t deltaticks (u4_t time) {
u4_t t = hal_ticks();
s4_t d = time - t;
if( d<=0 ) return 0; // in the past
if( (d>>16)!=0 ) return 0xFFFF; // far ahead
return (u2_t)d;
}
void hal_waitUntil (u4_t time) {
while( deltaticks(time) != 0 ); // busy wait until timestamp is reached
}
// check and rewind for target time
u1_t hal_checkTimer (u4_t time) {
u2_t dt;
myTIMER.Instance->SR &= ~TIM_SR_CC1IF; // clear any pending interrupts
if((dt = deltaticks(time)) < 5) { // event is now (a few ticks ahead)
myTIMER.Instance->DIER &= ~TIM_DIER_CC1IE; // disable IE
return 1;
} else { // rewind timer (fully or to exact time))
myTIMER.Instance->CCR1 = myTIMER.Instance->CNT + dt; // set comparator
myTIMER.Instance->DIER |= TIM_DIER_CC1IE; // enable IE
myTIMER.Instance->CCER |= TIM_CCER_CC1E; // enable capture/compare uint 2
return 0;
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim->Instance == myTIMER.Instance){
HAL.ticks++;
}
}
// -----------------------------------------------------------------------------
// IRQ
void hal_disableIRQs () {
__disable_irq();
//__set_BASEPRI(1 << 4);
HAL.irqlevel++;
}
void hal_enableIRQs () {
if(--HAL.irqlevel == 0) {
__enable_irq();
//__set_BASEPRI(0);
}
}
void hal_sleep () {
// low power sleep mode
#ifndef CFG_no_low_power_sleep_mode
// PWR->CR |= PWR_CR_LPSDSR;
#endif
// suspend execution until IRQ, regardless of the CPSR I-bit
__WFI();
}
// -----------------------------------------------------------------------------
void hal_init () {
memset(&HAL, 0x00, sizeof(HAL));
hal_disableIRQs();
// configure radio I/O and interrupt handler
hal_io_init();
// configure radio SPI
hal_spi_init();
// configure timer and interrupt handler
hal_time_init();
hal_enableIRQs();
}
void hal_failed () {
// HALT...
hal_disableIRQs();
hal_sleep();
while(1);
}

2229
src/lmic.c Normal file

File diff suppressed because it is too large Load Diff

573
src/main.c Normal file
View File

@ -0,0 +1,573 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lmic.h"
#include "debug.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
char floatBuffer[20];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
// include security credentials OTAA, check secconfig_example.h for more information
#include "secconfig.h"
#ifdef DISABLE_JOIN
// These callbacks are only used in over-the-air activation, so they are
// left empty here. We cannot leave them out completely otherwise the linker will complain.
// DISABLE_JOIN is set in config.h for using ABP
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }
#else
void os_getArtEui (u1_t* buf) { memcpy(buf, APPEUI, 8);}
void os_getDevEui (u1_t* buf) { memcpy(buf, DEVEUI, 8);}
void os_getDevKey (u1_t* buf) { memcpy(buf, APPKEY, 16);}
#endif
void initsensor(){
// Here you init your sensors
}
void initfunc (osjob_t* j) {
// intialize sensor hardware
initsensor();
// reset MAC state
LMIC_reset();
// Set static session parameters when using ABP.
// Instead of dynamically establishing a session
// by joining the network, precomputed session parameters are be provided.
#ifdef DISABLE_JOIN
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy(appskey, APPSKEY, sizeof(APPSKEY));
memcpy(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession(0x1, DEVADDR, nwkskey, appskey);
// These settings are needed for correct communication. By removing them you
// get empty downlink messages
// Disable ADR
LMIC_setAdrMode(0);
// TTN uses SF9 for its RX2 window.
LMIC.dn2Dr = DR_SF9;
// prevent some downlink messages, TTN advanced setup is set to the default 5
LMIC.rxDelay = 5;
// Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
LMIC_setDrTxpow(DR_SF12, 14);
#else
// start joining
LMIC_startJoining();
#endif
// init done - onEvent() callback will be invoked...
}
u2_t readsensor(){
u2_t value = 0xDF; /// read from evrything ...make your own sensor
return value;
}
static osjob_t reportjob;
// report sensor value every minute
static void reportfunc (osjob_t* j) {
// read sensor
u2_t val = readsensor();
debug_val("val = ", val);
// prepare and schedule data for transmission
LMIC.frame[0] = val << 8;
LMIC.frame[1] = val;
LMIC_setTxData2(1, LMIC.frame, 2, 0); // (port 1, 2 bytes, unconfirmed)
// reschedule job in 60 seconds
os_setTimedCallback(j, os_getTime()+sec2osticks(300), reportfunc);
}
static osjob_t testjob;
static void testfunc (osjob_t* j){
debug_str("Hallo Welt \n");
// reschedule job in 6 seconds
os_setTimedCallback(j, os_getTime()+sec2osticks(1), testfunc);
}
//////////////////////////////////////////////////
// LMIC EVENT CALLBACK
//////////////////////////////////////////////////
void onEvent (ev_t ev) {
debug_event(ev);
switch(ev) {
// network joined, session established
case EV_JOINING:
debug_str("try joining\r\n");
break;
case EV_JOINED:
debug_led(1);
// kick-off periodic sensor job
reportfunc(&reportjob);
break;
case EV_JOIN_FAILED:
debug_str("join failed\r\n");
break;
case EV_SCAN_TIMEOUT:
debug_str("EV_SCAN_TIMEOUT\r\n");
break;
case EV_BEACON_FOUND:
debug_str("EV_BEACON_FOUND\r\n");
break;
case EV_BEACON_MISSED:
debug_str("EV_BEACON_MISSED\r\n");
break;
case EV_BEACON_TRACKED:
debug_str("EV_BEACON_TRACKED\r\n");
break;
case EV_RFU1:
debug_str("EV_RFU1\r\n");
break;
case EV_REJOIN_FAILED:
debug_str("EV_REJOIN_FAILED\r\n");
break;
case EV_TXCOMPLETE:
debug_str("EV_TXCOMPLETE (includes waiting for RX windows)\r\n");
if (LMIC.txrxFlags & TXRX_ACK)
debug_str("Received ack\r\n");
if (LMIC.dataLen) {
debug_str("Received ");
debug_str((const char*)LMIC.dataLen);
debug_str(" bytes of payload\r\n");
}
break;
case EV_LOST_TSYNC:
debug_str("EV_LOST_TSYNC\r\n");
break;
case EV_RESET:
debug_str("EV_RESET\r\n");
break;
case EV_RXCOMPLETE:
// data received in ping slot
debug_str("EV_RXCOMPLETE\r\n");
break;
case EV_LINK_DEAD:
debug_str("EV_LINK_DEAD\r\n");
break;
case EV_LINK_ALIVE:
debug_str("EV_LINK_ALIVE\r\n");
break;
default:
debug_str("Unknown event\r\n");
break;
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2); // <----------- change to your setup
__HAL_SPI_ENABLE(&hspi1); // <----------- change to your setup
osjob_t initjob;
// initialize runtime env
os_init();
// initialize debug library
debug_init();
// setup initial job
os_setCallback(&initjob, initfunc);
// execute scheduled jobs and events
// os_setTimedCallback(&testjob, os_getTime()+sec2osticks(1), testfunc);
os_setTimedCallback(&reportjob, os_getTime()+sec2osticks(300), reportfunc);
os_runloop();
// (not reached)
return 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_DIV4;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief SPI1 Initialization Function
* @param None
* @retval None
*/
static void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI1_Init 2 */
/* USER CODE END SPI1_Init 2 */
}
/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 250-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 65535-1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_OC_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_TIMING;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief USART2 Initialization Function
* @param None
* @retval None
*/
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 9600;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, LED_Pin|NSS_Pin|RST_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : LED_Pin NSS_Pin RST_Pin */
GPIO_InitStruct.Pin = LED_Pin|NSS_Pin|RST_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : DIO0_Pin */
GPIO_InitStruct.Pin = DIO0_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DIO0_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : DIO1_Pin DIO2_Pin */
GPIO_InitStruct.Pin = DIO1_Pin|DIO2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

122
src/oslmic.c Normal file
View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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.
*/
#include "lmic.h"
// RUNTIME STATE
static struct {
osjob_t* scheduledjobs;
osjob_t* runnablejobs;
} OS;
void os_init () {
memset(&OS, 0x00, sizeof(OS));
hal_init();
radio_init();
LMIC_init();
}
ostime_t os_getTime () {
return hal_ticks();
}
// unlink job from queue, return if removed
static int unlinkjob (osjob_t** pnext, osjob_t* job) {
for( ; *pnext; pnext = &((*pnext)->next)) {
if(*pnext == job) { // unlink
*pnext = job->next;
return 1;
}
}
return 0;
}
// clear scheduled job
void os_clearCallback (osjob_t* job) {
hal_disableIRQs();
unlinkjob(&OS.scheduledjobs, job) || unlinkjob(&OS.runnablejobs, job);
hal_enableIRQs();
}
// schedule immediately runnable job
void os_setCallback (osjob_t* job, osjobcb_t cb) {
osjob_t** pnext;
hal_disableIRQs();
// remove if job was already queued
unlinkjob(&OS.runnablejobs, job);
// fill-in job
job->func = cb;
job->next = NULL;
// add to end of run queue
for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next));
*pnext = job;
hal_enableIRQs();
}
// schedule timed job
void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) {
osjob_t** pnext;
hal_disableIRQs();
// remove if job was already queued
unlinkjob(&OS.scheduledjobs, job);
// fill-in job
job->deadline = time;
job->func = cb;
job->next = NULL;
// insert into schedule
for(pnext=&OS.scheduledjobs; *pnext; pnext=&((*pnext)->next)) {
if((*pnext)->deadline - time > 0) { // (cmp diff, not abs!)
// enqueue before next element and stop
job->next = *pnext;
break;
}
}
*pnext = job;
hal_enableIRQs();
}
// execute jobs from timer and from run queue
void os_runloop () {
while(1) {
osjob_t* j = NULL;
hal_disableIRQs();
// check for runnable jobs
if(OS.runnablejobs) {
j = OS.runnablejobs;
OS.runnablejobs = j->next;
} else if(OS.scheduledjobs && hal_checkTimer(OS.scheduledjobs->deadline)) { // check for expired timed jobs
j = OS.scheduledjobs;
OS.scheduledjobs = j->next;
} else { // nothing pending
hal_sleep(); // wake by irq (timer already restarted)
}
hal_enableIRQs();
if(j) { // run job callback
j->func(j);
}
}
}

857
src/radio.c Normal file
View File

@ -0,0 +1,857 @@
/*
* Copyright (c) 2014-2016 IBM 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 <organization> 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 <COPYRIGHT HOLDER> 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.
*/
#include "lmic.h"
// ----------------------------------------
// Registers Mapping
#define RegFifo 0x00 // common
#define RegOpMode 0x01 // common
#define FSKRegBitrateMsb 0x02
#define FSKRegBitrateLsb 0x03
#define FSKRegFdevMsb 0x04
#define FSKRegFdevLsb 0x05
#define RegFrfMsb 0x06 // common
#define RegFrfMid 0x07 // common
#define RegFrfLsb 0x08 // common
#define RegPaConfig 0x09 // common
#define RegPaRamp 0x0A // common
#define RegOcp 0x0B // common
#define RegLna 0x0C // common
#define FSKRegRxConfig 0x0D
#define LORARegFifoAddrPtr 0x0D
#define FSKRegRssiConfig 0x0E
#define LORARegFifoTxBaseAddr 0x0E
#define FSKRegRssiCollision 0x0F
#define LORARegFifoRxBaseAddr 0x0F
#define FSKRegRssiThresh 0x10
#define LORARegFifoRxCurrentAddr 0x10
#define FSKRegRssiValue 0x11
#define LORARegIrqFlagsMask 0x11
#define FSKRegRxBw 0x12
#define LORARegIrqFlags 0x12
#define FSKRegAfcBw 0x13
#define LORARegRxNbBytes 0x13
#define FSKRegOokPeak 0x14
#define LORARegRxHeaderCntValueMsb 0x14
#define FSKRegOokFix 0x15
#define LORARegRxHeaderCntValueLsb 0x15
#define FSKRegOokAvg 0x16
#define LORARegRxPacketCntValueMsb 0x16
#define LORARegRxpacketCntValueLsb 0x17
#define LORARegModemStat 0x18
#define LORARegPktSnrValue 0x19
#define FSKRegAfcFei 0x1A
#define LORARegPktRssiValue 0x1A
#define FSKRegAfcMsb 0x1B
#define LORARegRssiValue 0x1B
#define FSKRegAfcLsb 0x1C
#define LORARegHopChannel 0x1C
#define FSKRegFeiMsb 0x1D
#define LORARegModemConfig1 0x1D
#define FSKRegFeiLsb 0x1E
#define LORARegModemConfig2 0x1E
#define FSKRegPreambleDetect 0x1F
#define LORARegSymbTimeoutLsb 0x1F
#define FSKRegRxTimeout1 0x20
#define LORARegPreambleMsb 0x20
#define FSKRegRxTimeout2 0x21
#define LORARegPreambleLsb 0x21
#define FSKRegRxTimeout3 0x22
#define LORARegPayloadLength 0x22
#define FSKRegRxDelay 0x23
#define LORARegPayloadMaxLength 0x23
#define FSKRegOsc 0x24
#define LORARegHopPeriod 0x24
#define FSKRegPreambleMsb 0x25
#define LORARegFifoRxByteAddr 0x25
#define LORARegModemConfig3 0x26
#define FSKRegPreambleLsb 0x26
#define FSKRegSyncConfig 0x27
#define LORARegFeiMsb 0x28
#define FSKRegSyncValue1 0x28
#define LORAFeiMib 0x29
#define FSKRegSyncValue2 0x29
#define LORARegFeiLsb 0x2A
#define FSKRegSyncValue3 0x2A
#define FSKRegSyncValue4 0x2B
#define LORARegRssiWideband 0x2C
#define FSKRegSyncValue5 0x2C
#define FSKRegSyncValue6 0x2D
#define FSKRegSyncValue7 0x2E
#define FSKRegSyncValue8 0x2F
#define FSKRegPacketConfig1 0x30
#define FSKRegPacketConfig2 0x31
#define LORARegDetectOptimize 0x31
#define FSKRegPayloadLength 0x32
#define FSKRegNodeAdrs 0x33
#define LORARegInvertIQ 0x33
#define FSKRegBroadcastAdrs 0x34
#define FSKRegFifoThresh 0x35
#define FSKRegSeqConfig1 0x36
#define FSKRegSeqConfig2 0x37
#define LORARegDetectionThreshold 0x37
#define FSKRegTimerResol 0x38
#define FSKRegTimer1Coef 0x39
#define LORARegSyncWord 0x39
#define FSKRegTimer2Coef 0x3A
#define FSKRegImageCal 0x3B
#define FSKRegTemp 0x3C
#define FSKRegLowBat 0x3D
#define FSKRegIrqFlags1 0x3E
#define FSKRegIrqFlags2 0x3F
#define RegDioMapping1 0x40 // common
#define RegDioMapping2 0x41 // common
#define RegVersion 0x42 // common
// #define RegAgcRef 0x43 // common
// #define RegAgcThresh1 0x44 // common
// #define RegAgcThresh2 0x45 // common
// #define RegAgcThresh3 0x46 // common
// #define RegPllHop 0x4B // common
// #define RegTcxo 0x58 // common
#define RegPaDac 0x5A // common
// #define RegPll 0x5C // common
// #define RegPllLowPn 0x5E // common
// #define RegFormerTemp 0x6C // common
// #define RegBitRateFrac 0x70 // common
// ----------------------------------------
// spread factors and mode for RegModemConfig2
#define SX1272_MC2_FSK 0x00
#define SX1272_MC2_SF7 0x70
#define SX1272_MC2_SF8 0x80
#define SX1272_MC2_SF9 0x90
#define SX1272_MC2_SF10 0xA0
#define SX1272_MC2_SF11 0xB0
#define SX1272_MC2_SF12 0xC0
// bandwidth for RegModemConfig1
#define SX1272_MC1_BW_125 0x00
#define SX1272_MC1_BW_250 0x40
#define SX1272_MC1_BW_500 0x80
// coding rate for RegModemConfig1
#define SX1272_MC1_CR_4_5 0x08
#define SX1272_MC1_CR_4_6 0x10
#define SX1272_MC1_CR_4_7 0x18
#define SX1272_MC1_CR_4_8 0x20
#define SX1272_MC1_IMPLICIT_HEADER_MODE_ON 0x04 // required for receive
#define SX1272_MC1_RX_PAYLOAD_CRCON 0x02
#define SX1272_MC1_LOW_DATA_RATE_OPTIMIZE 0x01 // mandated for SF11 and SF12
// transmit power configuration for RegPaConfig
#define SX1272_PAC_PA_SELECT_PA_BOOST 0x80
#define SX1272_PAC_PA_SELECT_RFIO_PIN 0x00
// sx1276 RegModemConfig1
#define SX1276_MC1_BW_125 0x70
#define SX1276_MC1_BW_250 0x80
#define SX1276_MC1_BW_500 0x90
#define SX1276_MC1_CR_4_5 0x02
#define SX1276_MC1_CR_4_6 0x04
#define SX1276_MC1_CR_4_7 0x06
#define SX1276_MC1_CR_4_8 0x08
#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
// sx1276 RegModemConfig2
#define SX1276_MC2_RX_PAYLOAD_CRCON 0x04
// sx1276 RegModemConfig3
#define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE 0x08
#define SX1276_MC3_AGCAUTO 0x04
// preamble for lora networks (nibbles swapped)
#define LORA_MAC_PREAMBLE 0x34
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1 0x0A
#ifdef CFG_sx1276_radio
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x70
#elif CFG_sx1272_radio
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74
#endif
// ----------------------------------------
// Constants for radio registers
#define OPMODE_LORA 0x80
#define OPMODE_MASK 0x07
#define OPMODE_SLEEP 0x00
#define OPMODE_STANDBY 0x01
#define OPMODE_FSTX 0x02
#define OPMODE_TX 0x03
#define OPMODE_FSRX 0x04
#define OPMODE_RX 0x05
#define OPMODE_RX_SINGLE 0x06
#define OPMODE_CAD 0x07
// ----------------------------------------
// Bits masking the corresponding IRQs from the radio
#define IRQ_LORA_RXTOUT_MASK 0x80
#define IRQ_LORA_RXDONE_MASK 0x40
#define IRQ_LORA_CRCERR_MASK 0x20
#define IRQ_LORA_HEADER_MASK 0x10
#define IRQ_LORA_TXDONE_MASK 0x08
#define IRQ_LORA_CDDONE_MASK 0x04
#define IRQ_LORA_FHSSCH_MASK 0x02
#define IRQ_LORA_CDDETD_MASK 0x01
#define IRQ_FSK1_MODEREADY_MASK 0x80
#define IRQ_FSK1_RXREADY_MASK 0x40
#define IRQ_FSK1_TXREADY_MASK 0x20
#define IRQ_FSK1_PLLLOCK_MASK 0x10
#define IRQ_FSK1_RSSI_MASK 0x08
#define IRQ_FSK1_TIMEOUT_MASK 0x04
#define IRQ_FSK1_PREAMBLEDETECT_MASK 0x02
#define IRQ_FSK1_SYNCADDRESSMATCH_MASK 0x01
#define IRQ_FSK2_FIFOFULL_MASK 0x80
#define IRQ_FSK2_FIFOEMPTY_MASK 0x40
#define IRQ_FSK2_FIFOLEVEL_MASK 0x20
#define IRQ_FSK2_FIFOOVERRUN_MASK 0x10
#define IRQ_FSK2_PACKETSENT_MASK 0x08
#define IRQ_FSK2_PAYLOADREADY_MASK 0x04
#define IRQ_FSK2_CRCOK_MASK 0x02
#define IRQ_FSK2_LOWBAT_MASK 0x01
// ----------------------------------------
// DIO function mappings D0D1D2D3
#define MAP_DIO0_LORA_RXDONE 0x00 // 00------
#define MAP_DIO0_LORA_TXDONE 0x40 // 01------
#define MAP_DIO1_LORA_RXTOUT 0x00 // --00----
#define MAP_DIO1_LORA_NOP 0x30 // --11----
#define MAP_DIO2_LORA_NOP 0xC0 // ----11--
#define MAP_DIO0_FSK_READY 0x00 // 00------ (packet sent / payload ready)
#define MAP_DIO1_FSK_NOP 0x30 // --11----
#define MAP_DIO2_FSK_TXNOP 0x04 // ----01--
#define MAP_DIO2_FSK_TIMEOUT 0x08 // ----10--
// FSK IMAGECAL defines
#define RF_IMAGECAL_AUTOIMAGECAL_MASK 0x7F
#define RF_IMAGECAL_AUTOIMAGECAL_ON 0x80
#define RF_IMAGECAL_AUTOIMAGECAL_OFF 0x00 // Default
#define RF_IMAGECAL_IMAGECAL_MASK 0xBF
#define RF_IMAGECAL_IMAGECAL_START 0x40
#define RF_IMAGECAL_IMAGECAL_RUNNING 0x20
#define RF_IMAGECAL_IMAGECAL_DONE 0x00 // Default
// RADIO STATE
// (initialized by radio_init(), used by radio_rand1())
static u1_t randbuf[16];
#ifdef CFG_sx1276_radio
#define LNA_RX_GAIN (0x20|0x1)
#elif CFG_sx1272_radio
#define LNA_RX_GAIN (0x20|0x03)
#else
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
#endif
static void writeReg (u1_t addr, u1_t data ) {
hal_pin_nss(0);
hal_spi(addr | 0x80);
hal_spi(data);
hal_pin_nss(1);
}
static u1_t readReg (u1_t addr) {
hal_pin_nss(0);
hal_spi(addr & 0x7F);
u1_t val = hal_spi(0x00);
hal_pin_nss(1);
return val;
}
static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) {
hal_pin_nss(0);
hal_spi(addr | 0x80);
for (u1_t i=0; i<len; i++) {
hal_spi(buf[i]);
}
hal_pin_nss(1);
}
static void readBuf (u1_t addr, xref2u1_t buf, u1_t len) {
hal_pin_nss(0);
hal_spi(addr & 0x7F);
for (u1_t i=0; i<len; i++) {
buf[i] = hal_spi(0x00);
}
hal_pin_nss(1);
}
static void opmode (u1_t mode) {
writeReg(RegOpMode, (readReg(RegOpMode) & ~OPMODE_MASK) | mode);
}
static void opmodeLora() {
u1_t u = OPMODE_LORA;
#ifdef CFG_sx1276_radio
u |= 0x8; // TBD: sx1276 high freq
#endif
writeReg(RegOpMode, u);
}
static void opmodeFSK() {
u1_t u = 0;
#ifdef CFG_sx1276_radio
u |= 0x8; // TBD: sx1276 high freq
#endif
writeReg(RegOpMode, u);
}
// configure LoRa modem (cfg1, cfg2)
static void configLoraModem () {
sf_t sf = getSf(LMIC.rps);
#ifdef CFG_sx1276_radio
u1_t mc1 = 0, mc2 = 0, mc3 = 0;
switch (getBw(LMIC.rps)) {
case BW125: mc1 |= SX1276_MC1_BW_125; break;
case BW250: mc1 |= SX1276_MC1_BW_250; break;
case BW500: mc1 |= SX1276_MC1_BW_500; break;
default:
ASSERT(0);
}
switch( getCr(LMIC.rps) ) {
case CR_4_5: mc1 |= SX1276_MC1_CR_4_5; break;
case CR_4_6: mc1 |= SX1276_MC1_CR_4_6; break;
case CR_4_7: mc1 |= SX1276_MC1_CR_4_7; break;
case CR_4_8: mc1 |= SX1276_MC1_CR_4_8; break;
default:
ASSERT(0);
}
if (getIh(LMIC.rps)) {
mc1 |= SX1276_MC1_IMPLICIT_HEADER_MODE_ON;
writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
}
// set ModemConfig1
writeReg(LORARegModemConfig1, mc1);
mc2 = (SX1272_MC2_SF7 + ((sf-1)<<4));
if (getNocrc(LMIC.rps) == 0) {
mc2 |= SX1276_MC2_RX_PAYLOAD_CRCON;
}
writeReg(LORARegModemConfig2, mc2);
mc3 = SX1276_MC3_AGCAUTO;
if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) {
mc3 |= SX1276_MC3_LOW_DATA_RATE_OPTIMIZE;
}
writeReg(LORARegModemConfig3, mc3);
#elif CFG_sx1272_radio
u1_t mc1 = (getBw(LMIC.rps)<<6);
switch( getCr(LMIC.rps) ) {
case CR_4_5: mc1 |= SX1272_MC1_CR_4_5; break;
case CR_4_6: mc1 |= SX1272_MC1_CR_4_6; break;
case CR_4_7: mc1 |= SX1272_MC1_CR_4_7; break;
case CR_4_8: mc1 |= SX1272_MC1_CR_4_8; break;
}
if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) {
mc1 |= SX1272_MC1_LOW_DATA_RATE_OPTIMIZE;
}
if (getNocrc(LMIC.rps) == 0) {
mc1 |= SX1272_MC1_RX_PAYLOAD_CRCON;
}
if (getIh(LMIC.rps)) {
mc1 |= SX1272_MC1_IMPLICIT_HEADER_MODE_ON;
writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
}
// set ModemConfig1
writeReg(LORARegModemConfig1, mc1);
// set ModemConfig2 (sf, AgcAutoOn=1 SymbTimeoutHi=00)
writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x04);
#if CFG_TxContinuousMode
// Only for testing
// set ModemConfig2 (sf, TxContinuousMode=1, AgcAutoOn=1 SymbTimeoutHi=00)
writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x06);
#endif
#else
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
#endif /* CFG_sx1272_radio */
}
static void configChannel () {
// set frequency: FQ = (FRF * 32 Mhz) / (2 ^ 19)
u8_t frf = ((u8_t)LMIC.freq << 19) / 32000000;
writeReg(RegFrfMsb, (u1_t)(frf>>16));
writeReg(RegFrfMid, (u1_t)(frf>> 8));
writeReg(RegFrfLsb, (u1_t)(frf>> 0));
}
static void configPower () {
#ifdef CFG_sx1276_radio
// no boost used for now
s1_t pw = (s1_t)LMIC.txpow;
if(pw >= 17) {
pw = 15;
} else if(pw < 2) {
pw = 2;
}
// check board type for BOOST pin
writeReg(RegPaConfig, (u1_t)(0x80|(pw&0xf)));
writeReg(RegPaDac, readReg(RegPaDac)|0x4);
#elif CFG_sx1272_radio
// set PA config (2-17 dBm using PA_BOOST)
s1_t pw = (s1_t)LMIC.txpow;
if(pw > 17) {
pw = 17;
} else if(pw < 2) {
pw = 2;
}
writeReg(RegPaConfig, (u1_t)(0x80|(pw-2)));
#else
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
#endif /* CFG_sx1272_radio */
}
static void txfsk () {
// select FSK modem (from sleep mode)
writeReg(RegOpMode, 0x10); // FSK, BT=0.5
ASSERT(readReg(RegOpMode) == 0x10);
// enter standby mode (required for FIFO loading))
opmode(OPMODE_STANDBY);
// set bitrate
writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
writeReg(FSKRegBitrateLsb, 0x80);
// set frequency deviation
writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
writeReg(FSKRegFdevLsb, 0x99);
// frame and packet handler settings
writeReg(FSKRegPreambleMsb, 0x00);
writeReg(FSKRegPreambleLsb, 0x05);
writeReg(FSKRegSyncConfig, 0x12);
writeReg(FSKRegPacketConfig1, 0xD0);
writeReg(FSKRegPacketConfig2, 0x40);
writeReg(FSKRegSyncValue1, 0xC1);
writeReg(FSKRegSyncValue2, 0x94);
writeReg(FSKRegSyncValue3, 0xC1);
// configure frequency
configChannel();
// configure output power
configPower();
// set the IRQ mapping DIO0=PacketSent DIO1=NOP DIO2=NOP
writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TXNOP);
// initialize the payload size and address pointers
writeReg(FSKRegPayloadLength, LMIC.dataLen+1); // (insert length byte into payload))
// download length byte and buffer to the radio FIFO
writeReg(RegFifo, LMIC.dataLen);
writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
// enable antenna switch for TX
hal_pin_rxtx(1);
// now we actually start the transmission
opmode(OPMODE_TX);
}
static void txlora () {
// select LoRa modem (from sleep mode)
//writeReg(RegOpMode, OPMODE_LORA);
opmodeLora();
ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
// enter standby mode (required for FIFO loading))
opmode(OPMODE_STANDBY);
// configure LoRa modem (cfg1, cfg2)
configLoraModem();
// configure frequency
configChannel();
// configure output power
writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec
configPower();
// set sync word
writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP);
// clear all radio IRQ flags
writeReg(LORARegIrqFlags, 0xFF);
// mask all IRQs but TxDone
writeReg(LORARegIrqFlagsMask, ~IRQ_LORA_TXDONE_MASK);
// initialize the payload size and address pointers
writeReg(LORARegFifoTxBaseAddr, 0x00);
writeReg(LORARegFifoAddrPtr, 0x00);
writeReg(LORARegPayloadLength, LMIC.dataLen);
// download buffer to the radio FIFO
writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
// enable antenna switch for TX
hal_pin_rxtx(1);
// now we actually start the transmission
opmode(OPMODE_TX);
}
// start transmitter (buf=LMIC.frame, len=LMIC.dataLen)
static void starttx () {
ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
if(getSf(LMIC.rps) == FSK) { // FSK modem
txfsk();
} else { // LoRa modem
txlora();
}
// the radio will go back to STANDBY mode as soon as the TX is finished
// the corresponding IRQ will inform us about completion.
}
enum { RXMODE_SINGLE, RXMODE_SCAN, RXMODE_RSSI };
static const u1_t rxlorairqmask[] = {
[RXMODE_SINGLE] = IRQ_LORA_RXDONE_MASK|IRQ_LORA_RXTOUT_MASK,
[RXMODE_SCAN] = IRQ_LORA_RXDONE_MASK,
[RXMODE_RSSI] = 0x00,
};
// start LoRa receiver (time=LMIC.rxtime, timeout=LMIC.rxsyms, result=LMIC.frame[LMIC.dataLen])
static void rxlora (u1_t rxmode) {
// select LoRa modem (from sleep mode)
opmodeLora();
ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
// enter standby mode (warm up))
opmode(OPMODE_STANDBY);
// don't use MAC settings at startup
if(rxmode == RXMODE_RSSI) { // use fixed settings for rssi scan
writeReg(LORARegModemConfig1, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1);
writeReg(LORARegModemConfig2, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2);
} else { // single or continuous rx mode
// configure LoRa modem (cfg1, cfg2)
configLoraModem();
// configure frequency
configChannel();
}
// set LNA gain
writeReg(RegLna, LNA_RX_GAIN);
// set max payload size
writeReg(LORARegPayloadMaxLength, 64);
// use inverted I/Q signal (prevent mote-to-mote communication)
// XXX: use flag to switch on/off inversion
if (LMIC.noRXIQinversion) {
writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ) & ~(1<<6));
} else {
writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ)|(1<<6));
}
// set symbol timeout (for single rx)
writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms);
// set sync word
writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
// configure DIO mapping DIO0=RxDone DIO1=RxTout DIO2=NOP
writeReg(RegDioMapping1, MAP_DIO0_LORA_RXDONE|MAP_DIO1_LORA_RXTOUT|MAP_DIO2_LORA_NOP);
// clear all radio IRQ flags
writeReg(LORARegIrqFlags, 0xFF);
// enable required radio IRQs
writeReg(LORARegIrqFlagsMask, ~rxlorairqmask[rxmode]);
// enable antenna switch for RX
hal_pin_rxtx(0);
// now instruct the radio to receive
if (rxmode == RXMODE_SINGLE) { // single rx
hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
opmode(OPMODE_RX_SINGLE);
} else { // continous rx (scan or rssi)
opmode(OPMODE_RX);
}
}
static void rxfsk (u1_t rxmode) {
// only single rx (no continuous scanning, no noise sampling)
ASSERT( rxmode == RXMODE_SINGLE );
// select FSK modem (from sleep mode)
//writeReg(RegOpMode, 0x00); // (not LoRa)
opmodeFSK();
ASSERT((readReg(RegOpMode) & OPMODE_LORA) == 0);
// enter standby mode (warm up))
opmode(OPMODE_STANDBY);
// configure frequency
configChannel();
// set LNA gain
//writeReg(RegLna, 0x20|0x03); // max gain, boost enable
writeReg(RegLna, LNA_RX_GAIN);
// configure receiver
writeReg(FSKRegRxConfig, 0x1E); // AFC auto, AGC, trigger on preamble?!?
// set receiver bandwidth
writeReg(FSKRegRxBw, 0x0B); // 50kHz SSb
// set AFC bandwidth
writeReg(FSKRegAfcBw, 0x12); // 83.3kHz SSB
// set preamble detection
writeReg(FSKRegPreambleDetect, 0xAA); // enable, 2 bytes, 10 chip errors
// set sync config
writeReg(FSKRegSyncConfig, 0x12); // no auto restart, preamble 0xAA, enable, fill FIFO, 3 bytes sync
// set packet config
writeReg(FSKRegPacketConfig1, 0xD8); // var-length, whitening, crc, no auto-clear, no adr filter
writeReg(FSKRegPacketConfig2, 0x40); // packet mode
// set sync value
writeReg(FSKRegSyncValue1, 0xC1);
writeReg(FSKRegSyncValue2, 0x94);
writeReg(FSKRegSyncValue3, 0xC1);
// set preamble timeout
writeReg(FSKRegRxTimeout2, 0xFF);//(LMIC.rxsyms+1)/2);
// set bitrate
writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
writeReg(FSKRegBitrateLsb, 0x80);
// set frequency deviation
writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
writeReg(FSKRegFdevLsb, 0x99);
// configure DIO mapping DIO0=PayloadReady DIO1=NOP DIO2=TimeOut
writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TIMEOUT);
// enable antenna switch for RX
hal_pin_rxtx(0);
// now instruct the radio to receive
hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
opmode(OPMODE_RX); // no single rx mode available in FSK
}
static void startrx (u1_t rxmode) {
ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
if(getSf(LMIC.rps) == FSK) { // FSK modem
rxfsk(rxmode);
} else { // LoRa modem
rxlora(rxmode);
}
// the radio will go back to STANDBY mode as soon as the RX is finished
// or timed out, and the corresponding IRQ will inform us about completion.
}
// get random seed from wideband noise rssi
void radio_init () {
hal_disableIRQs();
// manually reset radio
#ifdef CFG_sx1276_radio
hal_pin_rst(0); // drive RST pin low
#else
hal_pin_rst(1); // drive RST pin high
#endif
hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us
hal_pin_rst(2); // configure RST pin floating!
hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms
opmode(OPMODE_SLEEP);
// some sanity checks, e.g., read version number
u1_t v = readReg(RegVersion);
#ifdef CFG_sx1276_radio
ASSERT(v == 0x12 );
#elif CFG_sx1272_radio
ASSERT(v == 0x22);
#else
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
#endif
// seed 15-byte randomness via noise rssi
rxlora(RXMODE_RSSI);
while( (readReg(RegOpMode) & OPMODE_MASK) != OPMODE_RX ); // continuous rx
for(int i=1; i<16; i++) {
for(int j=0; j<8; j++) {
u1_t b; // wait for two non-identical subsequent least-significant bits
while( (b = readReg(LORARegRssiWideband) & 0x01) == (readReg(LORARegRssiWideband) & 0x01) );
randbuf[i] = (randbuf[i] << 1) | b;
}
}
randbuf[0] = 16; // set initial index
#ifdef CFG_sx1276mb1_board
// chain calibration
writeReg(RegPaConfig, 0);
// Launch Rx chain calibration for LF band
writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
while((readReg(FSKRegImageCal)&RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING){ ; }
// Sets a Frequency in HF band
u4_t frf = 868000000;
writeReg(RegFrfMsb, (u1_t)(frf>>16));
writeReg(RegFrfMid, (u1_t)(frf>> 8));
writeReg(RegFrfLsb, (u1_t)(frf>> 0));
// Launch Rx chain calibration for HF band
writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
while((readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING) { ; }
#endif /* CFG_sx1276mb1_board */
opmode(OPMODE_SLEEP);
hal_enableIRQs();
}
// return next random byte derived from seed buffer
// (buf[0] holds index of next byte to be returned)
u1_t radio_rand1 () {
u1_t i = randbuf[0];
ASSERT( i != 0 );
if( i==16 ) {
os_aes(AES_ENC, randbuf, 16); // encrypt seed with any key
i = 0;
}
u1_t v = randbuf[i++];
randbuf[0] = i;
return v;
}
u1_t radio_rssi () {
hal_disableIRQs();
u1_t r = readReg(LORARegRssiValue);
hal_enableIRQs();
return r;
}
static const u2_t LORA_RXDONE_FIXUP[] = {
[FSK] = us2osticks(0), // ( 0 ticks)
[SF7] = us2osticks(0), // ( 0 ticks)
[SF8] = us2osticks(1648), // ( 54 ticks)
[SF9] = us2osticks(3265), // ( 107 ticks)
[SF10] = us2osticks(7049), // ( 231 ticks)
[SF11] = us2osticks(13641), // ( 447 ticks)
[SF12] = us2osticks(31189), // (1022 ticks)
};
// called by hal ext IRQ handler
// (radio goes to stanby mode after tx/rx operations)
void radio_irq_handler (u1_t dio) {
#if CFG_TxContinuousMode
// clear radio IRQ flags
writeReg(LORARegIrqFlags, 0xFF);
u1_t p = readReg(LORARegFifoAddrPtr);
writeReg(LORARegFifoAddrPtr, 0x00);
u1_t s = readReg(RegOpMode);
u1_t c = readReg(LORARegModemConfig2);
opmode(OPMODE_TX);
return;
#else /* ! CFG_TxContinuousMode */
ostime_t now = os_getTime();
if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem
u1_t flags = readReg(LORARegIrqFlags);
if( flags & IRQ_LORA_TXDONE_MASK ) {
// save exact tx time
LMIC.txend = now - us2osticks(43); // TXDONE FIXUP
} else if( flags & IRQ_LORA_RXDONE_MASK ) {
// save exact rx time
if(getBw(LMIC.rps) == BW125) {
now -= LORA_RXDONE_FIXUP[getSf(LMIC.rps)];
}
LMIC.rxtime = now;
// read the PDU and inform the MAC that we received something
LMIC.dataLen = (readReg(LORARegModemConfig1) & SX1272_MC1_IMPLICIT_HEADER_MODE_ON) ?
readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes);
// set FIFO read address pointer
writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr));
// now read the FIFO
readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
// read rx quality parameters
LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63)
} else if( flags & IRQ_LORA_RXTOUT_MASK ) {
// indicate timeout
LMIC.dataLen = 0;
}
// mask all radio IRQs
writeReg(LORARegIrqFlagsMask, 0xFF);
// clear radio IRQ flags
writeReg(LORARegIrqFlags, 0xFF);
} else { // FSK modem
u1_t flags1 = readReg(FSKRegIrqFlags1);
u1_t flags2 = readReg(FSKRegIrqFlags2);
if( flags2 & IRQ_FSK2_PACKETSENT_MASK ) {
// save exact tx time
LMIC.txend = now;
} else if( flags2 & IRQ_FSK2_PAYLOADREADY_MASK ) {
// save exact rx time
LMIC.rxtime = now;
// read the PDU and inform the MAC that we received something
LMIC.dataLen = readReg(FSKRegPayloadLength);
// now read the FIFO
readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
// read rx quality parameters
LMIC.snr = 0; // determine snr
LMIC.rssi = 0; // determine rssi
} else if( flags1 & IRQ_FSK1_TIMEOUT_MASK ) {
// indicate timeout
LMIC.dataLen = 0;
} else {
while(1);
}
}
// go from stanby to sleep
opmode(OPMODE_SLEEP);
// run os job (use preset func ptr)
os_setCallback(&LMIC.osjob, LMIC.osjob.func);
#endif /* ! CFG_TxContinuousMode */
}
void os_radio (u1_t mode) {
hal_disableIRQs();
switch (mode) {
case RADIO_RST:
// put radio to sleep
opmode(OPMODE_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();
}

313
src/stm32l0xx_hal_msp.c Normal file
View File

@ -0,0 +1,313 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32l0xx_hal_msp.c
* @brief This file provides code for the MSP Initialization
* and de-Initialization codes.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN Define */
/* USER CODE END Define */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN Macro */
/* USER CODE END Macro */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* External functions --------------------------------------------------------*/
/* USER CODE BEGIN ExternalFunctions */
/* USER CODE END ExternalFunctions */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
/* USER CODE BEGIN MspInit 0 */
/* USER CODE END MspInit 0 */
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
/* System interrupt init*/
/* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */
}
/**
* @brief SPI MSP Initialization
* This function configures the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspInit 0 */
/* USER CODE END SPI1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN SPI1_MspInit 1 */
/* USER CODE END SPI1_MspInit 1 */
}
}
/**
* @brief SPI MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
if(hspi->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspDeInit 0 */
/* USER CODE END SPI1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SPI1_CLK_DISABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
/* USER CODE BEGIN SPI1_MspDeInit 1 */
/* USER CODE END SPI1_MspDeInit 1 */
}
}
/**
* @brief TIM_OC MSP Initialization
* This function configures the hardware resources used in this example
* @param htim_oc: TIM_OC handle pointer
* @retval None
*/
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef* htim_oc)
{
if(htim_oc->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspInit 0 */
/* USER CODE END TIM2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM2_CLK_ENABLE();
/* TIM2 interrupt Init */
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/* USER CODE BEGIN TIM2_MspInit 1 */
/* USER CODE END TIM2_MspInit 1 */
}
}
/**
* @brief TIM_OC MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param htim_oc: TIM_OC handle pointer
* @retval None
*/
void HAL_TIM_OC_MspDeInit(TIM_HandleTypeDef* htim_oc)
{
if(htim_oc->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspDeInit 0 */
/* USER CODE END TIM2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM2_CLK_DISABLE();
/* TIM2 interrupt DeInit */
HAL_NVIC_DisableIRQ(TIM2_IRQn);
/* USER CODE BEGIN TIM2_MspDeInit 1 */
/* USER CODE END TIM2_MspDeInit 1 */
}
}
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspInit 0 */
/* USER CODE END USART1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USART1 GPIO Configuration
PB6 ------> USART1_TX
PB7 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_USART1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN USART1_MspInit 1 */
/* USER CODE END USART1_MspInit 1 */
}
else if(huart->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspInit 0 */
/* USER CODE END USART2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN USART2_MspInit 1 */
/* USER CODE END USART2_MspInit 1 */
}
}
/**
* @brief UART MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
if(huart->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspDeInit 0 */
/* USER CODE END USART1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART1_CLK_DISABLE();
/**USART1 GPIO Configuration
PB6 ------> USART1_TX
PB7 ------> USART1_RX
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);
/* USER CODE BEGIN USART1_MspDeInit 1 */
/* USER CODE END USART1_MspDeInit 1 */
}
else if(huart->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspDeInit 0 */
/* USER CODE END USART2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART2_CLK_DISABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
/* USER CODE BEGIN USART2_MspDeInit 1 */
/* USER CODE END USART2_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

175
src/stm32l0xx_it.c Normal file
View File

@ -0,0 +1,175 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32l0xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32l0xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
extern TIM_HandleTypeDef htim2;
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/******************************************************************************/
/* Cortex-M0+ Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1)
{
}
/* USER CODE END NonMaskableInt_IRQn 1 */
}
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
/**
* @brief This function handles System service call via SWI instruction.
*/
void SVC_Handler(void)
{
/* USER CODE BEGIN SVC_IRQn 0 */
/* USER CODE END SVC_IRQn 0 */
/* USER CODE BEGIN SVC_IRQn 1 */
/* USER CODE END SVC_IRQn 1 */
}
/**
* @brief This function handles Pendable request for system service.
*/
void PendSV_Handler(void)
{
/* USER CODE BEGIN PendSV_IRQn 0 */
/* USER CODE END PendSV_IRQn 0 */
/* USER CODE BEGIN PendSV_IRQn 1 */
/* USER CODE END PendSV_IRQn 1 */
}
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
/******************************************************************************/
/* STM32L0xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32l0xx.s). */
/******************************************************************************/
/**
* @brief This function handles EXTI line 4 to 15 interrupts.
*/
void EXTI4_15_IRQHandler(void)
{
/* USER CODE BEGIN EXTI4_15_IRQn 0 */
/* USER CODE END EXTI4_15_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(DIO1_Pin);
HAL_GPIO_EXTI_IRQHandler(DIO2_Pin);
HAL_GPIO_EXTI_IRQHandler(DIO0_Pin);
/* USER CODE BEGIN EXTI4_15_IRQn 1 */
/* USER CODE END EXTI4_15_IRQn 1 */
}
/**
* @brief This function handles TIM2 global interrupt.
*/
void TIM2_IRQHandler(void)
{
/* USER CODE BEGIN TIM2_IRQn 0 */
/* USER CODE END TIM2_IRQn 0 */
HAL_TIM_IRQHandler(&htim2);
/* USER CODE BEGIN TIM2_IRQn 1 */
/* USER CODE END TIM2_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

273
src/system_stm32l0xx.c Normal file
View File

@ -0,0 +1,273 @@
/**
******************************************************************************
* @file system_stm32l0xx.c
* @author MCD Application Team
* @brief CMSIS Cortex-M0+ Device Peripheral Access Layer System Source File.
*
* This file provides two functions and one global variable to be called from
* user application:
* - SystemInit(): This function is called at startup just after reset and
* before branch to main program. This call is made inside
* the "startup_stm32l0xx.s" file.
*
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
* by the user application to setup the SysTick
* timer or configure other parameters.
*
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
* be called whenever the core clock is changed
* during program execution.
*
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32l0xx_system
* @{
*/
/** @addtogroup STM32L0xx_System_Private_Includes
* @{
*/
#include "stm32l0xx.h"
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (MSI_VALUE)
#define MSI_VALUE ((uint32_t)2097152U) /*!< Value of the Internal oscillator in Hz*/
#endif /* MSI_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @}
*/
/** @addtogroup STM32L0xx_System_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @addtogroup STM32L0xx_System_Private_Defines
* @{
*/
/************************* Miscellaneous Configuration ************************/
/* Note: Following vector table addresses must be defined in line with linker
configuration. */
/*!< Uncomment the following line if you need to relocate the vector table
anywhere in Flash or Sram, else the vector table is kept at the automatic
remap of boot address selected */
/* #define USER_VECT_TAB_ADDRESS */
#if defined(USER_VECT_TAB_ADDRESS)
/*!< Uncomment the following line if you need to relocate your vector Table
in Sram else user remap will be done in Flash. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#else
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#endif /* VECT_TAB_SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
/******************************************************************************/
/**
* @}
*/
/** @addtogroup STM32L0xx_System_Private_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32L0xx_System_Private_Variables
* @{
*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock; then there
is no need to call the 2 first functions listed above, since SystemCoreClock
variable is updated automatically.
*/
uint32_t SystemCoreClock = 2097152U; /* 32.768 kHz * 2^6 */
const uint8_t AHBPrescTable[16] = {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U};
const uint8_t APBPrescTable[8] = {0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U};
const uint8_t PLLMulTable[9] = {3U, 4U, 6U, 8U, 12U, 16U, 24U, 32U, 48U};
/**
* @}
*/
/** @addtogroup STM32L0xx_System_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32L0xx_System_Private_Functions
* @{
*/
/**
* @brief Setup the microcontroller system.
* @param None
* @retval None
*/
void SystemInit (void)
{
/* Configure the Vector Table location add offset address ------------------*/
#if defined (USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
}
/**
* @brief Update SystemCoreClock variable according to Clock Register Values.
* The SystemCoreClock variable contains the core clock (HCLK), it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock (HCLK) changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is MSI, SystemCoreClock will contain the MSI
* value as defined by the MSI range.
*
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
*
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
*
* (*) HSI_VALUE is a constant defined in stm32l0xx_hal.h file (default value
* 16 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (**) HSE_VALUE is a constant defined in stm32l0xx_hal.h file (default value
* 8 MHz), user has to ensure that HSE_VALUE is same as the real
* frequency of the crystal used. Otherwise, this function may
* have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
* @param None
* @retval None
*/
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0U, pllmul = 0U, plldiv = 0U, pllsource = 0U, msirange = 0U;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case 0x00U: /* MSI used as system clock */
msirange = (RCC->ICSCR & RCC_ICSCR_MSIRANGE) >> RCC_ICSCR_MSIRANGE_Pos;
SystemCoreClock = (32768U * (1U << (msirange + 1U)));
break;
case 0x04U: /* HSI used as system clock */
if ((RCC->CR & RCC_CR_HSIDIVF) != 0U)
{
SystemCoreClock = HSI_VALUE / 4U;
}
else
{
SystemCoreClock = HSI_VALUE;
}
break;
case 0x08U: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
default: /* PLL used as system clock */
/* Get PLL clock source and multiplication factor ----------------------*/
pllmul = RCC->CFGR & RCC_CFGR_PLLMUL;
plldiv = RCC->CFGR & RCC_CFGR_PLLDIV;
pllmul = PLLMulTable[(pllmul >> RCC_CFGR_PLLMUL_Pos)];
plldiv = (plldiv >> RCC_CFGR_PLLDIV_Pos) + 1U;
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
if (pllsource == 0x00U)
{
/* HSI oscillator clock selected as PLL clock entry */
if ((RCC->CR & RCC_CR_HSIDIVF) != 0U)
{
SystemCoreClock = (((HSI_VALUE / 4U) * pllmul) / plldiv);
}
else
{
SystemCoreClock = (((HSI_VALUE) * pllmul) / plldiv);
}
}
else
{
/* HSE selected as PLL clock entry */
SystemCoreClock = (((HSE_VALUE) * pllmul) / plldiv);
}
break;
}
/* Compute HCLK clock frequency --------------------------------------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/

272
startup_stm32l051xx.s Normal file
View File

@ -0,0 +1,272 @@
/**
******************************************************************************
* @file startup_stm32l051xx.s
* @author MCD Application Team
* @brief STM32L051xx Devices vector table for GCC toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M0+ processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
.syntax unified
.cpu cortex-m0plus
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr r0, =_estack
mov sp, r0 /* set stack pointer */
/* Call the clock system initialization function.*/
bl SystemInit
/* Copy the data segment initializers from flash to SRAM */
ldr r0, =_sdata
ldr r1, =_edata
ldr r2, =_sidata
movs r3, #0
b LoopCopyDataInit
CopyDataInit:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopyDataInit:
adds r4, r0, r3
cmp r4, r1
bcc CopyDataInit
/* Zero fill the bss segment. */
ldr r2, =_sbss
ldr r4, =_ebss
movs r3, #0
b LoopFillZerobss
FillZerobss:
str r3, [r2]
adds r2, r2, #4
LoopFillZerobss:
cmp r2, r4
bcc FillZerobss
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
LoopForever:
b LoopForever
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
*
* @param None
* @retval : None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M0. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word 0
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler /* Window WatchDog */
.word PVD_IRQHandler /* PVD through EXTI Line detection */
.word RTC_IRQHandler /* RTC through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */
.word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */
.word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
.word 0 /* Reserved */
.word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
.word DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */
.word DMA1_Channel4_5_6_7_IRQHandler /* DMA1 Channel 4, Channel 5, Channel 6 and Channel 7*/
.word ADC1_COMP_IRQHandler /* ADC1, COMP1 and COMP2 */
.word LPTIM1_IRQHandler /* LPTIM1 */
.word 0 /* Reserved */
.word TIM2_IRQHandler /* TIM2 */
.word 0 /* Reserved */
.word TIM6_IRQHandler /* TIM6 */
.word 0 /* Reserved */
.word 0 /* Reserved */
.word TIM21_IRQHandler /* TIM21 */
.word 0 /* Reserved */
.word TIM22_IRQHandler /* TIM22 */
.word I2C1_IRQHandler /* I2C1 */
.word I2C2_IRQHandler /* I2C2 */
.word SPI1_IRQHandler /* SPI1 */
.word SPI2_IRQHandler /* SPI2 */
.word USART1_IRQHandler /* USART1 */
.word USART2_IRQHandler /* USART2 */
.word LPUART1_IRQHandler /* LPUART1 */
.word 0 /* Reserved */
.word 0 /* Reserved */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak RTC_IRQHandler
.thumb_set RTC_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_1_IRQHandler
.thumb_set EXTI0_1_IRQHandler,Default_Handler
.weak EXTI2_3_IRQHandler
.thumb_set EXTI2_3_IRQHandler,Default_Handler
.weak EXTI4_15_IRQHandler
.thumb_set EXTI4_15_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_3_IRQHandler
.thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler
.weak DMA1_Channel4_5_6_7_IRQHandler
.thumb_set DMA1_Channel4_5_6_7_IRQHandler,Default_Handler
.weak ADC1_COMP_IRQHandler
.thumb_set ADC1_COMP_IRQHandler,Default_Handler
.weak LPTIM1_IRQHandler
.thumb_set LPTIM1_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM6_IRQHandler
.thumb_set TIM6_IRQHandler,Default_Handler
.weak TIM21_IRQHandler
.thumb_set TIM21_IRQHandler,Default_Handler
.weak TIM22_IRQHandler
.thumb_set TIM22_IRQHandler,Default_Handler
.weak I2C1_IRQHandler
.thumb_set I2C1_IRQHandler,Default_Handler
.weak I2C2_IRQHandler
.thumb_set I2C2_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak LPUART1_IRQHandler
.thumb_set LPUART1_IRQHandler,Default_Handler

11
test/README Executable file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html