Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## SF10 fallback supervisor (v4.8.0)
- read some documentation: [README_SF10_FALLBACK.md](https://github.com/JulioFerreiraDev/SWL2001/blob/fa3afffdd08a38a8519973190d59865d6b38ec95/docs/README_SF10_FALLBACK.md)

# LoRa Basic Modem

**LoRa Basic Modem** proposes an full implementation of the [TS001-LoRaWAN L2 1.0.4](https://resources.lora-alliance.org/technical-specifications/ts001-1-0-4-lorawan-l2-1-0-4-specification) and [Regional Parameters RP2-1.0.3](https://resources.lora-alliance.org/technical-specifications/rp2-1-0-3-lorawan-regional-parameters) specifications.
Expand Down
24 changes: 24 additions & 0 deletions docs/README_SF10_FALLBACK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SF10 fallback supervisor (SWL2001 v4.8.0)

This repository contains a change on top of **SWL2001 v4.8.0** to implement an **SF10 fallback supervisor** based on **confirmed uplink ACK failures**.

## What was changed
- **File:** `lbm_examples/main_examples/main_periodical_uplink.c`
- **Goal:** when consecutive confirmed uplinks do not receive ACK, temporarily force a fallback in **SF10** (ADR custom profile), and return to default ADR after a fixed number of cycles.

## Flowchart
![SF10 fallback flowchart](figures/flowchart_sf10_fallback.png)

## Key variables (as implemented)
- `consecutive_ack_failures`: counts consecutive confirmed uplinks without ACK
- `sf10_fallback_active`: indicates whether fallback mode is active
- `sf10_fallback_usage`: counts cycles spent in fallback mode
- `last_uplink_confirmed_requested`: indicates whether the last uplink requested confirmation

## Trigger and exit criteria
- Enter fallback when `consecutive_ack_failures > 5` and `sf10_fallback_active == false`
- While fallback is active, increment `sf10_fallback_usage`
- Exit fallback when `sf10_fallback_usage >= 20`, restoring default ADR

## How to cite
Use the GitHub Release `v4.8.0-sf10-fallback.1` and the Zenodo DOI (if enabled).
Binary file added docs/figures/flowchart_sf10_fallback.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
138 changes: 135 additions & 3 deletions lbm_examples/main_examples/main_periodical_uplink.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*!
/*!
* \file main_periodical_uplink.c
*
* \brief main program for periodical example
Expand Down Expand Up @@ -165,6 +165,10 @@ static const uint8_t user_app_key[16] = USER_LORAWAN_APP_KEY;
#define DELAY_FIRST_MSG_AFTER_JOIN 60
#endif

/* ===================== Fallback SF10 por falhas de ACK (TXDONE) ===================== */
#define ACK_FAILURES_THRESHOLD_TO_FALLBACK 5
#define SF10_FALLBACK_USAGE_THRESHOLD_TO_EXIT 20

/*
* -----------------------------------------------------------------------------
* --- PRIVATE TYPES -----------------------------------------------------------
Expand Down Expand Up @@ -192,6 +196,34 @@ static smtc_modem_relay_tx_config_t relay_config = { 0 };
static uint8_t chip_eui[SMTC_MODEM_EUI_LENGTH] = { 0 };
static uint8_t chip_pin[SMTC_MODEM_PIN_LENGTH] = { 0 };
#endif

/* ===================== Estado do fallback SF10 (ACK) ===================== */
static int consecutive_ack_failures = 0; // conta quantas tentativas seguidas não tiveram confirmação (ACK)
static int sf10_fallback_usage = 0; // conta quantos uplinks (ou ciclos) foram feitos sob o fallback SF10
static bool sf10_fallback_active = false; // indica se o modo fallback está ativo

static bool last_uplink_confirmed_requested = false;

// Distribuição custom: força DR0 (SF10 em AU915) como preferencial.
static const uint8_t custom_adr_distribution_sf10[SMTC_MODEM_CUSTOM_ADR_DATA_LENGTH] = {
0xFF, // DR0
0x00, // DR1
0x00, // DR2
0x00, // DR3
0x00, // DR4
0x00, // DR5
0x00, // DR6
0x00, // DR7
0x00, // DR8
0x00, // DR9
0x00, // DR10
0x00, // DR11
0x00, // DR12
0x00, // DR13
0x00, // DR14
0x00 // DR15
};

/*
* -----------------------------------------------------------------------------
* --- PRIVATE FUNCTIONS DECLARATION -------------------------------------------
Expand All @@ -217,6 +249,11 @@ static void user_button_callback( void* context );
*/
static void send_uplink_counter_on_port( uint8_t port );

/* Fallback SF10 por falhas de ACK (TXDONE) */
static void apply_default_adr( const uint8_t stack_id );
static void apply_sf10_fallback( const uint8_t stack_id );
static void sf10_fallback_supervisor_on_txdone( const uint8_t stack_id, const smtc_modem_event_t* ev );

/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS DEFINITION ---------------------------------------------
Expand Down Expand Up @@ -290,6 +327,92 @@ void main_periodical_uplink( void )
* --- PRIVATE FUNCTIONS DEFINITION --------------------------------------------
*/

static void apply_default_adr( const uint8_t stack_id )
{
// O array custom é ignorado nesse perfil com ADR normal, mas precisa existir.
uint8_t custom_vazio[SMTC_MODEM_CUSTOM_ADR_DATA_LENGTH];
memset( custom_vazio, 0, sizeof( custom_vazio ) );

(void) smtc_modem_adr_set_profile( stack_id, SMTC_MODEM_ADR_PROFILE_NETWORK_CONTROLLED, custom_vazio );

sf10_fallback_active = false;
sf10_fallback_usage = 0;
consecutive_ack_failures = 0;
}

static void apply_sf10_fallback( const uint8_t stack_id )
{
// Entra no modo "forçar SF10" via perfil custom
(void) smtc_modem_adr_set_profile( stack_id, SMTC_MODEM_ADR_PROFILE_CUSTOM, custom_adr_distribution_sf10 );

sf10_fallback_active = true;
sf10_fallback_usage = 0;
}

static void sf10_fallback_supervisor_on_txdone( const uint8_t stack_id, const smtc_modem_event_t* ev )
{
if( ev == NULL )
{
return;
}

if( ev->event_type != SMTC_MODEM_EVENT_TXDONE )
{
return;
}

/* =========================
* 1) Se está em fallback, conta uso e avalia saída.
* Em fallback, NÃO zera consecutive_ack_failures mesmo se TXDONE_CONFIRMED.
* ========================= */
if( sf10_fallback_active )
{
sf10_fallback_usage++;

if( sf10_fallback_usage >= SF10_FALLBACK_USAGE_THRESHOLD_TO_EXIT )
{
apply_default_adr( stack_id );
// apply_default_adr já zera sf10_fallback_usage e consecutive_ack_failures
}
return;
}

/* =========================
* 2) Contar ACK se o uplink foi solicitado como confirmado.
* ========================= */
if( last_uplink_confirmed_requested == false )
{
return;
}

/* =========================
* 3) Se houve ACK, zera falhas consecutivas.
* ========================= */
if( ev->event_data.txdone.status == SMTC_MODEM_EVENT_TXDONE_CONFIRMED )
{
consecutive_ack_failures = 0;
return;
}

/* =========================
* 4) Sem ACK -> incrementa falhas e pode entrar em fallback.
* ========================= */
consecutive_ack_failures++;

if( consecutive_ack_failures > ACK_FAILURES_THRESHOLD_TO_FALLBACK )
{
apply_sf10_fallback( stack_id );

// Ao entrar em fallback, uso_fallback_sf10 = 0
sf10_fallback_usage = 0;
sf10_fallback_active = true;

return;
}

return;
}

static void modem_event_callback( void )
{
SMTC_HAL_TRACE_MSG_COLOR( "Modem event callback\n", HAL_DBG_TRACE_COLOR_BLUE );
Expand Down Expand Up @@ -355,7 +478,7 @@ static void modem_event_callback( void )
relay_config.backoff = 0; // 4;
ASSERT_SMTC_MODEM_RC( smtc_modem_relay_tx_enable( stack_id, &relay_config ) );
#endif

ASSERT_SMTC_MODEM_RC( smtc_modem_join_network( stack_id ) );
break;

Expand All @@ -380,6 +503,9 @@ static void modem_event_callback( void )
case SMTC_MODEM_EVENT_TXDONE:
SMTC_HAL_TRACE_INFO( "Event received: TXDONE\n" );
SMTC_HAL_TRACE_INFO( "Transmission done \n" );

sf10_fallback_supervisor_on_txdone( stack_id, &current_event );

break;

case SMTC_MODEM_EVENT_DOWNDATA:
Expand Down Expand Up @@ -551,7 +677,13 @@ static void send_uplink_counter_on_port( uint8_t port )
buff[1] = ( uplink_counter >> 16 ) & 0xFF;
buff[2] = ( uplink_counter >> 8 ) & 0xFF;
buff[3] = ( uplink_counter & 0xFF );
ASSERT_SMTC_MODEM_RC( smtc_modem_request_uplink( STACK_ID, port, false, buff, 4 ) );

const bool confirmado = true;

// guarda se este uplink foi solicitado como confirmado
last_uplink_confirmed_requested = confirmado;

ASSERT_SMTC_MODEM_RC( smtc_modem_request_uplink( STACK_ID, port, confirmado, buff, 4 ) );
// Increment uplink counter
uplink_counter++;
}
Expand Down