2018-07-15 22:11:11 +02:00
/*******************************************************************************
2018-07-21 21:54:29 +02:00
*
* ttn - esp32 - The Things Network device library for ESP - IDF / SX127x
*
2018-07-15 22:11:11 +02:00
* Copyright ( c ) 2018 Manuel Bleichenbacher
*
2018-07-21 21:54:29 +02:00
* Licensed under MIT License
* https : //opensource.org/licenses/MIT
2018-07-15 22:11:11 +02:00
*
2018-07-23 17:59:07 +02:00
* High - level API for ttn - esp32 .
2018-07-15 22:11:11 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-07-17 19:46:29 +02:00
# include "freertos/FreeRTOS.h"
# include "esp_event.h"
2018-07-15 22:11:11 +02:00
# include "esp_log.h"
2018-07-23 09:46:45 +02:00
# include "TheThingsNetwork.h"
2018-10-02 20:25:40 +02:00
# include "hal/hal_esp32.h"
# include "lmic/lmic.h"
2018-10-27 14:45:55 +02:00
# include "TTNProvisioning.h"
2018-07-23 09:46:45 +02:00
2018-07-15 22:11:11 +02:00
2018-07-19 21:19:32 +02:00
enum ClientAction
{
eActionUnrelated ,
eActionJoining ,
eActionSending
} ;
2018-07-15 22:11:11 +02:00
static const char * TAG = " ttn " ;
static TheThingsNetwork * ttnInstance ;
2018-07-19 21:19:32 +02:00
static QueueHandle_t resultQueue ;
static ClientAction clientAction = eActionUnrelated ;
2018-10-27 14:45:55 +02:00
static TTNProvisioning provisioning ;
2018-07-17 19:46:29 +02:00
2018-07-15 22:11:11 +02:00
2018-07-17 22:07:35 +02:00
TheThingsNetwork : : TheThingsNetwork ( )
2018-10-27 14:45:55 +02:00
: messageCallback ( nullptr )
2018-07-15 22:11:11 +02:00
{
2018-07-23 17:36:28 +02:00
# if defined(TTN_IS_DISABLED)
ESP_LOGE ( TAG , " TTN is disabled. Configure a frequency plan using 'make menuconfig' " ) ;
ASSERT ( 0 ) ;
esp_restart ( ) ;
# endif
2018-10-27 14:45:55 +02:00
ASSERT ( ttnInstance = = nullptr ) ;
2018-07-15 22:11:11 +02:00
ttnInstance = this ;
2018-10-27 23:55:36 +02:00
ttn_hal . initCriticalSection ( ) ;
2018-07-15 22:11:11 +02:00
}
TheThingsNetwork : : ~ TheThingsNetwork ( )
{
// nothing to do
}
void TheThingsNetwork : : configurePins ( spi_host_device_t spi_host , uint8_t nss , uint8_t rxtx , uint8_t rst , uint8_t dio0 , uint8_t dio1 )
{
lmic_pins . spi_host = spi_host ;
lmic_pins . nss = nss ;
lmic_pins . rxtx = rxtx ;
lmic_pins . rst = rst ;
lmic_pins . dio0 = dio0 ;
lmic_pins . dio1 = dio1 ;
os_init ( ) ;
reset ( ) ;
2018-07-19 21:19:32 +02:00
resultQueue = xQueueCreate ( 12 , sizeof ( int ) ) ;
2018-10-27 14:45:55 +02:00
ASSERT ( resultQueue ! = nullptr ) ;
2018-10-27 23:55:36 +02:00
ttn_hal . startBackgroundTask ( ) ;
2018-07-15 22:11:11 +02:00
}
void TheThingsNetwork : : reset ( )
{
2018-10-27 23:55:36 +02:00
ttn_hal . enterCriticalSection ( ) ;
2018-07-15 22:11:11 +02:00
LMIC_reset ( ) ;
2018-10-27 23:55:36 +02:00
ttn_hal . leaveCriticalSection ( ) ;
2018-07-15 22:11:11 +02:00
}
2018-07-17 22:07:35 +02:00
bool TheThingsNetwork : : provision ( const char * devEui , const char * appEui , const char * appKey )
2018-07-15 22:11:11 +02:00
{
2018-10-27 14:45:55 +02:00
if ( ! provisioning . decodeKeys ( devEui , appEui , appKey ) )
2018-07-20 21:19:53 +02:00
return false ;
2018-10-27 14:45:55 +02:00
return provisioning . saveKeys ( ) ;
2018-07-15 22:11:11 +02:00
}
2018-09-17 22:50:15 +02:00
bool TheThingsNetwork : : provisionWithMAC ( const char * appEui , const char * appKey )
{
2018-10-27 14:45:55 +02:00
if ( ! provisioning . fromMAC ( appEui , appKey ) )
2018-09-17 22:50:15 +02:00
return false ;
2018-10-27 14:45:55 +02:00
return provisioning . saveKeys ( ) ;
2018-09-17 22:50:15 +02:00
}
2018-10-27 19:19:55 +02:00
2018-07-23 09:46:45 +02:00
void TheThingsNetwork : : startProvisioningTask ( )
2018-07-15 22:11:11 +02:00
{
2018-10-27 19:19:55 +02:00
# if defined(TTN_HAS_AT_COMMANDS)
2018-10-27 14:45:55 +02:00
provisioning . startTask ( ) ;
2018-10-27 19:19:55 +02:00
# else
ESP_LOGE ( TAG , " AT commands are disabled. Change the configuration using 'make menuconfig' " ) ;
ASSERT ( 0 ) ;
esp_restart ( ) ;
2018-07-23 09:46:45 +02:00
# endif
2018-07-15 22:11:11 +02:00
}
2018-07-23 14:30:03 +02:00
void TheThingsNetwork : : waitForProvisioning ( )
{
2018-10-27 19:19:55 +02:00
# if defined(TTN_HAS_AT_COMMANDS)
2018-07-23 14:30:03 +02:00
if ( isProvisioned ( ) )
{
ESP_LOGI ( TAG , " Device is already provisioned " ) ;
return ;
}
2018-10-27 14:45:55 +02:00
while ( ! provisioning . haveKeys ( ) )
2018-07-23 14:30:03 +02:00
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
ESP_LOGI ( TAG , " Device successfully provisioned " ) ;
2018-10-27 19:19:55 +02:00
# else
ESP_LOGE ( TAG , " AT commands are disabled. Change the configuration using 'make menuconfig' " ) ;
ASSERT ( 0 ) ;
esp_restart ( ) ;
2018-07-23 14:30:03 +02:00
# endif
}
2018-07-23 09:46:45 +02:00
2018-07-17 22:07:35 +02:00
bool TheThingsNetwork : : join ( const char * devEui , const char * appEui , const char * appKey )
2018-07-15 22:11:11 +02:00
{
2018-10-27 14:45:55 +02:00
if ( ! provisioning . decodeKeys ( devEui , appEui , appKey ) )
2018-07-15 22:11:11 +02:00
return false ;
2018-07-20 21:19:53 +02:00
return joinCore ( ) ;
2018-07-15 22:11:11 +02:00
}
2018-07-17 22:07:35 +02:00
bool TheThingsNetwork : : join ( )
2018-07-15 22:11:11 +02:00
{
2018-10-27 14:45:55 +02:00
if ( ! provisioning . haveKeys ( ) )
2018-07-20 21:19:53 +02:00
{
2018-10-27 14:45:55 +02:00
if ( ! provisioning . restoreKeys ( false ) )
2018-07-20 21:19:53 +02:00
return false ;
}
return joinCore ( ) ;
}
bool TheThingsNetwork : : joinCore ( )
{
2018-10-27 14:45:55 +02:00
if ( ! provisioning . haveKeys ( ) )
2018-07-20 21:19:53 +02:00
{
ESP_LOGW ( TAG , " Device EUI, App EUI and/or App key have not been provided " ) ;
return false ;
}
2018-10-27 23:55:36 +02:00
ttn_hal . enterCriticalSection ( ) ;
2018-07-19 21:19:32 +02:00
clientAction = eActionJoining ;
2018-07-15 22:11:11 +02:00
LMIC_startJoining ( ) ;
2018-10-27 23:55:36 +02:00
ttn_hal . wakeUp ( ) ;
ttn_hal . leaveCriticalSection ( ) ;
2018-07-17 19:46:29 +02:00
2018-07-19 21:19:32 +02:00
int result = 0 ;
xQueueReceive ( resultQueue , & result , portMAX_DELAY ) ;
2018-07-17 19:46:29 +02:00
return result = = EV_JOINED ;
2018-07-15 22:11:11 +02:00
}
2018-07-21 18:07:36 +02:00
TTNResponseCode TheThingsNetwork : : transmitMessage ( const uint8_t * payload , size_t length , port_t port , bool confirm )
2018-07-15 22:11:11 +02:00
{
2018-10-27 23:55:36 +02:00
ttn_hal . enterCriticalSection ( ) ;
2018-07-15 22:11:11 +02:00
if ( LMIC . opmode & OP_TXRXPEND )
{
2018-10-27 23:55:36 +02:00
ttn_hal . leaveCriticalSection ( ) ;
2018-07-19 22:04:32 +02:00
return kTTNErrorTransmissionFailed ;
2018-07-15 22:11:11 +02:00
}
2018-07-19 21:19:32 +02:00
clientAction = eActionSending ;
2018-07-15 22:11:11 +02:00
LMIC_setTxData2 ( port , ( xref2u1_t ) payload , length , confirm ) ;
2018-10-27 23:55:36 +02:00
ttn_hal . wakeUp ( ) ;
ttn_hal . leaveCriticalSection ( ) ;
2018-07-17 19:46:29 +02:00
2018-07-19 21:19:32 +02:00
int result = 0 ;
xQueueReceive ( resultQueue , & result , portMAX_DELAY ) ;
2018-07-19 16:16:40 +02:00
if ( result = = EV_TXCOMPLETE )
{
bool hasRecevied = ( LMIC . txrxFlags & ( TXRX_DNW1 | TXRX_DNW2 ) ) ! = 0 ;
2018-10-27 14:45:55 +02:00
if ( hasRecevied & & messageCallback ! = nullptr )
2018-07-19 16:16:40 +02:00
{
port_t port = 0 ;
if ( ( LMIC . txrxFlags & TXRX_PORT ) )
port = LMIC . frame [ LMIC . dataBeg - 1 ] ;
2018-10-27 14:45:55 +02:00
const uint8_t * msg = nullptr ;
2018-07-19 22:04:32 +02:00
if ( LMIC . dataLen > 0 )
msg = LMIC . frame + LMIC . dataBeg ;
messageCallback ( msg , LMIC . dataLen , port ) ;
2018-07-19 16:16:40 +02:00
}
2018-07-19 22:04:32 +02:00
return kTTNSuccessfulTransmission ;
2018-07-19 16:16:40 +02:00
}
2018-07-19 22:04:32 +02:00
return kTTNErrorTransmissionFailed ;
2018-07-19 16:16:40 +02:00
}
2018-07-19 22:04:32 +02:00
void TheThingsNetwork : : onMessage ( TTNMessageCallback callback )
2018-07-19 16:16:40 +02:00
{
messageCallback = callback ;
2018-07-15 22:11:11 +02:00
}
2018-07-20 21:19:53 +02:00
bool TheThingsNetwork : : isProvisioned ( )
{
2018-10-27 14:45:55 +02:00
if ( provisioning . haveKeys ( ) )
2018-07-20 21:19:53 +02:00
return true ;
2018-10-27 14:45:55 +02:00
provisioning . restoreKeys ( true ) ;
2018-07-28 22:13:59 +02:00
2018-10-27 14:45:55 +02:00
return provisioning . haveKeys ( ) ;
2018-07-20 21:19:53 +02:00
}
2018-07-15 22:11:11 +02:00
// --- LMIC functions ---
# if CONFIG_LOG_DEFAULT_LEVEL >= 3
static const char * eventNames [ ] = {
2018-10-27 14:45:55 +02:00
nullptr ,
2018-07-15 22:11:11 +02:00
" EV_SCAN_TIMEOUT " , " EV_BEACON_FOUND " ,
" EV_BEACON_MISSED " , " EV_BEACON_TRACKED " , " EV_JOINING " ,
" EV_JOINED " , " EV_RFU1 " , " EV_JOIN_FAILED " , " EV_REJOIN_FAILED " ,
" EV_TXCOMPLETE " , " EV_LOST_TSYNC " , " EV_RESET " ,
2018-10-02 23:08:38 +02:00
" EV_RXCOMPLETE " , " EV_LINK_DEAD " , " EV_LINK_ALIVE " , " EV_SCAN_FOUND " ,
" EV_TXSTART "
2018-07-15 22:11:11 +02:00
} ;
# endif
void onEvent ( ev_t ev ) {
# if CONFIG_LOG_DEFAULT_LEVEL >= 3
2018-07-17 19:46:29 +02:00
ESP_LOGI ( TAG , " event %s " , eventNames [ ev ] ) ;
2018-07-15 22:11:11 +02:00
# endif
2018-07-17 19:46:29 +02:00
if ( ev = = EV_TXCOMPLETE ) {
if ( LMIC . txrxFlags & TXRX_ACK )
2018-07-19 16:16:40 +02:00
ESP_LOGI ( TAG , " ACK received \n " ) ;
2018-07-15 22:11:11 +02:00
}
2018-07-17 19:46:29 +02:00
2018-07-19 21:19:32 +02:00
if ( clientAction = = eActionUnrelated )
{
return ;
}
else if ( clientAction = = eActionJoining )
{
2018-07-23 15:29:37 +02:00
if ( ev ! = EV_JOINED & & ev ! = EV_REJOIN_FAILED & & ev ! = EV_RESET )
2018-07-19 21:19:32 +02:00
return ;
}
else
{
2018-07-23 15:29:37 +02:00
if ( ev ! = EV_TXCOMPLETE & & ev ! = EV_LINK_DEAD & & ev ! = EV_RESET )
2018-07-19 21:19:32 +02:00
return ;
}
2018-07-17 19:46:29 +02:00
int result = ev ;
2018-07-19 21:19:32 +02:00
clientAction = eActionUnrelated ;
xQueueSend ( resultQueue , & result , 100 / portTICK_PERIOD_MS ) ;
2018-07-15 22:11:11 +02:00
}