init commit

This commit is contained in:
2026-03-30 13:45:38 +03:00
commit 0b982e5d4d
570 changed files with 280071 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
The Clear BSD License
Copyright Semtech Corporation 2021. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the disclaimer
below) 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 Semtech corporation nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
THIS LICENSE. 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 SEMTECH CORPORATION 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.

View File

@@ -0,0 +1,141 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Release Notes for STM32WLxx SubGHz Physical Layer Middleware</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: 1;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
<link rel="stylesheet" href="_htmresc/mini-st_2020.css" />
<link rel="icon" type="image/x-icon" href="_htmresc/favicon.png" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div class="row">
<div class="col-sm-12 col-lg-4">
<center>
<h1 id="release-notes-for">Release Notes for</h1>
<h1 id="stm32wlxx-subghz-physical-layer-middleware"><mark>STM32WLxx SubGHz Physical Layer Middleware</mark></h1>
<p>Copyright © 2021 STMicroelectronics<br />
</p>
<a href="https://www.st.com" class="logo"><img src="_htmresc/st_logo_2020.png" alt="ST logo" /></a>
</center>
<h1 id="purpose">Purpose</h1>
<p>This Middleware provides the SubGHz Physical Layer for the stm32wlxx products. This covers</p>
<ul>
<li>STM32WLxx devices</li>
</ul>
<p>This driver is composed of the radio driver and radio interface under “stm32_radio_driver” directory.</p>
</div>
<section id="update-history" class="col-sm-12 col-lg-8">
<h1>Update History</h1>
<div class="collapse">
<input type="checkbox" id="collapse-section4" checked aria-hidden="true"> <label for="collapse-section4" aria-hidden="true"><strong>V1.3.1 / 28-Aug-2024</strong></label>
<div>
<h2 id="main-changes">Main Changes</h2>
<ul>
<li>Fix: Application hangs because MBMUXIF_LoraSendCmd() command stuck</li>
<li>Fix: typo in setting MaxPayloadLength for GENERIC_LORA in RadioSetRxGenericConfig</li>
<li>Release Notes update</li>
</ul>
<h2 id="known-limitations">Known limitations:</h2>
<p>None</p>
</div>
</div>
<div class="collapse">
<input type="checkbox" id="collapse-section4" checked aria-hidden="true"> <label for="collapse-section4" aria-hidden="true"><strong>V1.3.0 / 21-Oct-2022</strong></label>
<div>
<h2 id="main-changes">Main Changes</h2>
<ul>
<li>Feature: 169MHz validation support</li>
<li>Feature: Add LoRa-E support (LR-FHSS)</li>
<li>Feature: RF output optimization</li>
<li>Chore: Sync Word register addresses not matching Semtech SX1261/2 datasheet</li>
<li>Fix: SUBGHz GCFO registers not in line with the RM</li>
<li>Fix: AGC of radio stuck when jammed</li>
<li>Release Notes update</li>
</ul>
<h2 id="known-limitations">Known limitations:</h2>
<p>None</p>
</div>
</div>
<div class="collapse">
<input type="checkbox" id="collapse-section3" aria-hidden="true"> <label for="collapse-section3" aria-hidden="true"><strong>V1.2.0 / 14-Dec-2021</strong></label>
<div>
<h2 id="main-changes-1">Main Changes</h2>
<ul>
<li>Feature: Add defines RADIO_SIGFOX_ENABLE and RADIO_GENERIC_CONFIG_ENABLE to reduce code size when not needed</li>
<li>Feature: Add Tx GMSK support</li>
<li>Chore: Align register names with Reference Manual</li>
<li>Chore: Clarify node/broadcast address</li>
<li>Fix: Set_RxDutyCycle() function (Rx timeout Issue)</li>
<li>Licensing update: New way to declare licenses</li>
<li>Release Notes update</li>
</ul>
<h2 id="known-limitations-1">Known limitations:</h2>
<p>None</p>
</div>
</div>
<div class="collapse">
<input type="checkbox" id="collapse-section2" aria-hidden="true"> <label for="collapse-section2" aria-hidden="true"><strong>V1.1.0 / 29-Apr-2021</strong></label>
<div>
<h2 id="main-changes-2">Main Changes</h2>
<ul>
<li>fix: SMPS drive level init</li>
<li>fix: GENERIC_BPSK in RadioSetTxGenericConfig function (test mode)</li>
<li>fix: MODEM_BPSK is not handled in RadioSetModem in radio.c</li>
<li>feature: add cfo calculation</li>
<li>fix: reduce interrupt scope to minimize privilege stack code execution</li>
<li>feature:add long packet in radio_fw</li>
<li>feature: Support IBM whitening by firmware radio_fw</li>
<li>fix: Channel Activity Detection: antenna switch set in rx mode</li>
<li>fix: Deadlock of WL RF driver</li>
<li>fix: PingPong RxErrors when SF12, BW500, CR 4/8</li>
<li>feature: move GetFskBandwidthRegValue in radio_driver</li>
<li>fix: Incorrect LoRa PER Results</li>
<li>feature: align to LoRaWAN Semtech stack v4.4.7 integration - Radio Part</li>
</ul>
<h2 id="known-limitations-2">Known limitations:</h2>
<p>None</p>
</div>
</div>
<div class="collapse">
<input type="checkbox" id="collapse-section1" aria-hidden="true"> <label for="collapse-section1" aria-hidden="true"><strong>V1.0.0 / 21-Oct-2020</strong></label>
<div>
<h2 id="main-changes-3">Main Changes</h2>
<ul>
<li>First Release</li>
</ul>
<h2 id="known-limitations-3">Known limitations:</h2>
<p>None</p>
</div>
</div>
</section>
</div>
<footer class="sticky">
<div class="columns">
<div class="column" style="width:95%;">
<p>For complete documentation on STM32WLxx, visit: <a href="http://www.st.com/stm32wl">www.st.com/stm32wl</a></p>
<p><em>This release note uses up to date web standards and, for this reason, should not be opened with Internet Explorer but preferably with popular browsers such as Google Chrome, Mozilla Firefox, Opera or Microsoft Edge.</em></p>
</div><div class="column" style="width:5%;">
<p><abbr title="Based on template cx566953 version 2.0">Info</abbr></p>
</div>
</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><g fill="#13254a"><path d="M100 .212C44.868.212 0 44.889 0 99.788c0 55.132 44.868 100 100 100s100-44.868 100-100C200 44.889 155.132.212 100 .212zm0 181.164c-44.974 0-81.587-36.614-81.587-81.587 0-44.762 36.614-81.164 81.587-81.164 44.995 0 81.587 36.402 81.587 81.164 0 44.973-36.592 81.587-81.587 81.587z" style="fill: #e6007e;"/><path d="M141.1 88.127h-29.439V58.688c0-6.392-5.185-11.598-11.598-11.598-6.413 0-11.619 5.206-11.619 11.598v29.439H58.476c-6.392 0-11.598 5.185-11.598 11.598 0 6.413 5.206 11.619 11.598 11.619h29.968v29.968c0 6.392 5.206 11.598 11.619 11.598 6.413 0 11.598-5.206 11.598-11.598v-29.968H141.1c6.392 0 11.598-5.206 11.598-11.619 0-6.413-5.206-11.598-11.598-11.598z" style="fill: #e6007e;"/></g></svg>

After

Width:  |  Height:  |  Size: 830 B

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><g fill="#03234b"><path d="M170.934 64.569l-.04-.055-29.049 40.038-.057.079h14.867a59.366 59.366 0 0 1-1.488 15.615c-1.158 5.318-3.807 13.448-9.848 21.977-2.766 4.118-6.375 7.726-9.208 10.408-3.426 2.857-7.461 6.095-12 8.376-8.121 4.568-17.881 7.138-28.225 7.432-10.907.248-20.201-2.61-26.072-5.052-8.283-3.479-14.111-7.807-16.85-10.078-1.254-.956-2.25-1.907-3.057-2.676a28.662 28.662 0 0 0-1.157-1.069 158.874 158.874 0 0 0-1.479-1.362l-4.435-3.956 3.569 4.81.183.243c.2.263.548.722 1.048 1.389.276.334.579.747.93 1.226l.008.01c.689.939 1.546 2.107 2.664 3.322 3 3.536 8.178 8.801 15.808 13.801 5.969 3.866 15.672 8.901 28.001 10.935a79.05 79.05 0 0 0 12.485.998c7.97 0 15.651-1.228 22.828-3.649 6.366-1.877 12.192-4.981 17.053-7.771 6.16-3.936 10.817-7.586 14.654-11.488 8.084-7.899 14.884-17.913 19.15-28.199 3.259-7.594 5.456-15.727 6.529-24.175l.055-.425.083-.641H200l-29.066-40.063zM58.159 99.232l-12.655.563c-.097-.881-.159-1.986-.227-3.474a59.184 59.184 0 0 1 1.446-16.56c1.157-5.316 3.804-13.444 9.848-21.977 2.168-3.228 5.009-6.44 9.208-10.415 3.41-2.849 7.432-6.08 12.005-8.375 8.114-4.568 17.87-7.138 28.213-7.432 10.9-.25 20.196 2.607 26.072 5.045 8.258 3.473 14.105 7.812 16.857 10.091 1.257.951 2.253 1.904 3.057 2.673l.017.016c.43.411.801.766 1.136 1.051.475.438.841.777 1.091 1.01l.138.128.248.229 4.04 3.613-3.165-4.456c-.058-.083-.312-.417-.73-.971l-.507-.67a28.922 28.922 0 0 1-.901-1.192l-.02-.027c-.69-.945-1.548-2.121-2.677-3.346-3.002-3.537-8.182-8.803-15.813-13.801-5.964-3.865-15.662-8.9-27.997-10.935-8.484-1.363-21.496-2.009-35.313 2.651-6.355 1.88-12.186 4.983-17.054 7.772-6.163 3.944-10.82 7.595-14.654 11.488-8.079 7.894-14.882 17.909-19.155 28.2-3.268 7.624-5.463 15.757-6.523 24.173-.436 3.281-.642 5.421-.664 6.926L0 101.831l30.683 38.727.042.053 27.38-41.298.054-.081z" style="fill: #e6007e;"/></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -0,0 +1,139 @@
/*!
* @file lr_fhss_v1_base_types.h
*
* @brief Radio-independent LR-FHSS base type definitions, version 1
*
* The Clear BSD License
* Copyright Semtech Corporation 2021. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) 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 Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. 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 SEMTECH CORPORATION 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 LR_FHSS_V1_BASE_TYPES_H__
#define LR_FHSS_V1_BASE_TYPES_H__
/*
* -----------------------------------------------------------------------------
* --- DEPENDENCIES ------------------------------------------------------------
*/
#include <stdint.h>
#include <stdbool.h>
/*
* -----------------------------------------------------------------------------
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC CONSTANTS --------------------------------------------------------
*/
#define LR_FHSS_HDR_BYTES ( 10 )
#define LR_FHSS_HDR_BITS ( 8 * LR_FHSS_HDR_BYTES )
#define LR_FHSS_HALF_HDR_BYTES ( 5 )
#define LR_FHSS_HALF_HDR_BITS ( 8 * LR_FHSS_HALF_HDR_BYTES )
#define LR_FHSS_SYNC_WORD_BYTES ( 4 )
#define LR_FHSS_SYNC_WORD_BITS ( 8 * LR_FHSS_SYNC_WORD_BYTES )
#define LR_FHSS_MAX_PHY_PAYLOAD_BYTES ( 255 )
#define LR_FHSS_HEADER_BITS ( 114 )
#define LR_FHSS_FRAG_BITS ( 48 )
#define LR_FHSS_BLOCK_PREAMBLE_BITS ( 2 )
#define LR_FHSS_BLOCK_BITS ( LR_FHSS_FRAG_BITS + LR_FHSS_BLOCK_PREAMBLE_BITS )
/*
* -----------------------------------------------------------------------------
* --- PUBLIC TYPES ------------------------------------------------------------
*/
/*!
* @brief LR-FHSS modulation type
*/
typedef enum lr_fhss_v1_modulation_type_e
{
LR_FHSS_V1_MODULATION_TYPE_GMSK_488 = 0,
} lr_fhss_v1_modulation_type_t;
/*!
* @brief LR-FHSS coding rate
*/
typedef enum lr_fhss_v1_cr_e
{
LR_FHSS_V1_CR_5_6 = 0x00,
LR_FHSS_V1_CR_2_3 = 0x01,
LR_FHSS_V1_CR_1_2 = 0x02,
LR_FHSS_V1_CR_1_3 = 0x03,
} lr_fhss_v1_cr_t;
/*!
* @brief LR-FHSS grid
*/
typedef enum lr_fhss_v1_grid_e
{
LR_FHSS_V1_GRID_25391_HZ = 0x00,
LR_FHSS_V1_GRID_3906_HZ = 0x01,
} lr_fhss_v1_grid_t;
/*!
* @brief LR-FHSS bandwidth
*/
typedef enum lr_fhss_v1_bw_e
{
LR_FHSS_V1_BW_39063_HZ = 0x00,
LR_FHSS_V1_BW_85938_HZ = 0x01,
LR_FHSS_V1_BW_136719_HZ = 0x02,
LR_FHSS_V1_BW_183594_HZ = 0x03,
LR_FHSS_V1_BW_335938_HZ = 0x04,
LR_FHSS_V1_BW_386719_HZ = 0x05,
LR_FHSS_V1_BW_722656_HZ = 0x06,
LR_FHSS_V1_BW_773438_HZ = 0x07,
LR_FHSS_V1_BW_1523438_HZ = 0x08,
LR_FHSS_V1_BW_1574219_HZ = 0x09,
} lr_fhss_v1_bw_t;
/*!
* @brief LR-FHSS parameter structure
*/
typedef struct lr_fhss_v1_params_s
{
const uint8_t* sync_word; /**< 4-byte sync word */
lr_fhss_v1_modulation_type_t modulation_type;
lr_fhss_v1_cr_t cr;
lr_fhss_v1_grid_t grid;
lr_fhss_v1_bw_t bw;
bool enable_hopping;
uint8_t header_count; /**< Number of header blocks */
} lr_fhss_v1_params_t;
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
#endif // LR_FHSS_V1_BASE_TYPES_H__
/* --- EOF ------------------------------------------------------------------ */

View File

@@ -0,0 +1,474 @@
/*!
* \file radio.h
*
* \brief Radio driver API definition
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*/
/**
******************************************************************************
*
* Portions COPYRIGHT 2020 STMicroelectronics
*
* @file radio.h
* @author MCD Application Team
* @brief Radio driver API definition
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __RADIO_H__
#define __RADIO_H__
#ifdef __cplusplus
extern "C"
{
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "radio_def.h"
#include "radio_ex.h"
#include "lr_fhss_v1_base_types.h"
/* Private typedef -----------------------------------------------------------*/
/*!
* Radio driver internal state machine states definition
*/
typedef enum
{
RF_IDLE = 0, //!< The radio is idle
RF_RX_RUNNING, //!< The radio is in reception state
RF_TX_RUNNING, //!< The radio is in transmission state
RF_CAD, //!< The radio is doing channel activity detection
} RadioState_t;
typedef struct radio_lr_fhss_params_s
{
lr_fhss_v1_params_t lr_fhss_params;
uint32_t center_frequency_in_hz;
int8_t device_offset;
} radio_lr_fhss_params_t;
/*!
* Radio LR-FHSS configuration parameters
*/
typedef struct loramac_radio_lr_fhss_cfg_params_s
{
int8_t tx_rf_pwr_in_dbm; //!< Radio RF output power
radio_lr_fhss_params_t radio_lr_fhss_params; //!< LR-FHSS parameters
uint32_t tx_timeout_in_ms; //!< Radio tx timeout
} radio_lr_fhss_cfg_params_t;
/*!
* Radio LoRa time on air configuration parameters
*/
typedef struct loramac_radio_lr_fhss_time_on_air_params_s
{
radio_lr_fhss_params_t radio_lr_fhss_params; //!< LR-FHSS parameters
uint8_t pld_len_in_bytes; //!< LoRa payload length in bytes
} radio_lr_fhss_time_on_air_params_t;
/* Function prototypes -----------------------------------------------------------*/
/*!
* \brief Radio driver definition
*/
struct Radio_s
{
/*!
* \brief Initializes the radio
*
* \param [in] events Structure containing the driver callback functions
*/
void ( *Init )( RadioEvents_t *events );
/*!
* Return current radio status
*
* \return status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
*/
RadioState_t ( *GetStatus )( void );
/*!
* \brief Configures the radio with the given modem
*
* \param [in] modem Modem to be used [0: FSK, 1: LoRa]
*/
void ( *SetModem )( RadioModems_t modem );
/*!
* \brief Sets the channel frequency
*
* \param [in] freq Channel RF frequency
*/
void ( *SetChannel )( uint32_t freq );
/*!
* \brief Checks if the channel is free for the given time
*
* \remark The FSK modem is always used for this task as we can select the Rx bandwidth at will.
*
* \param [in] freq Channel RF frequency in Hertz
* \param [in] rxBandwidth Rx bandwidth in Hertz
* \param [in] rssiThresh RSSI threshold in dBm
* \param [in] maxCarrierSenseTime Max time in milliseconds while the RSSI is measured
*
* \retval isFree [true: Channel is free, false: Channel is not free]
*/
bool ( *IsChannelFree )( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
/*!
* \brief Generates a 32 bits random value based on the RSSI readings
*
* \remark This function sets the radio in LoRa modem mode and disables
* all interrupts.
* After calling this function either Radio.SetRxConfig or
* Radio.SetTxConfig functions must be called.
*
* \retval randomValue 32 bits random value
*/
uint32_t ( *Random )( void );
/*!
* \brief Sets the reception parameters
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] bandwidthAfc Sets the AFC Bandwidth (FSK only)
* FSK : >= 2600 and <= 250000 Hz
* LoRa: N/A ( set to 0 )
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \param [in] freqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \param [in] hopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \param [in] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \param [in] rxContinuous Sets the reception in continuous mode
* [false: single mode, true: continuous mode]
*/
void ( *SetRxConfig )( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint32_t bandwidthAfc, uint16_t preambleLen,
uint16_t symbTimeout, bool fixLen,
uint8_t payloadLen,
bool crcOn, bool freqHopOn, uint8_t hopPeriod,
bool iqInverted, bool rxContinuous );
/*!
* \brief Sets the transmission parameters
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] power Sets the output power [dBm]
* \param [in] fdev Sets the frequency deviation (FSK only)
* FSK : [Hz]
* LoRa: 0
* \param [in] bandwidth Sets the bandwidth (LoRa only)
* FSK : 0
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] crcOn Enables disables the CRC [0: OFF, 1: ON]
* \param [in] freqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \param [in] hopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \param [in] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \param [in] timeout Transmission timeout [ms]
*/
void ( *SetTxConfig )( RadioModems_t modem, int8_t power, uint32_t fdev,
uint32_t bandwidth, uint32_t datarate,
uint8_t coderate, uint16_t preambleLen,
bool fixLen, bool crcOn, bool freqHopOn,
uint8_t hopPeriod, bool iqInverted, uint32_t timeout );
/*!
* \brief Checks if the given RF frequency is supported by the hardware
*
* \param [in] frequency RF frequency to be checked
* \retval isSupported [true: supported, false: unsupported]
*/
bool ( *CheckRfFrequency )( uint32_t frequency );
/*!
* \brief Computes the packet time on air in ms for the given payload
*
* \remark Can only be called once SetRxConfig or SetTxConfig have been called
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
*
* \retval airTime Computed airTime (ms) for the given packet payload length
*/
uint32_t ( *TimeOnAir )( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn );
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
* the radio in transmission
*
* \param [in] buffer Buffer pointer
* \param [in] size Buffer size
*
* \retval status (OK, ERROR, ...)
*/
radio_status_t ( *Send )( uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the radio in sleep mode
*/
void ( *Sleep )( void );
/*!
* \brief Sets the radio in standby mode
*/
void ( *Standby )( void );
/*!
* \brief Sets the radio in reception mode for the given time
* \param [in] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
void ( *Rx )( uint32_t timeout );
/*!
* \brief Start a Channel Activity Detection
*/
void ( *StartCad )( void );
/*!
* \brief Sets the radio in continuous wave transmission mode
*
* \param [in] freq Channel RF frequency
* \param [in] power Sets the output power [dBm]
* \param [in] time Transmission mode timeout [s]
*/
void ( *SetTxContinuousWave )( uint32_t freq, int8_t power, uint16_t time );
/*!
* \brief Reads the current RSSI value
*
* \retval rssiValue Current RSSI value in [dBm]
*/
int16_t ( *Rssi )( RadioModems_t modem );
/*!
* \brief Writes the radio register at the specified address
*
* \param [in] addr Register address
* \param [in] data New register value
*/
void ( *Write )( uint16_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
*
* \param [in] addr Register address
* \retval data Register value
*/
uint8_t ( *Read )( uint16_t addr );
/*!
* \brief Writes multiple radio registers starting at address
*
* \param [in] addr First Radio register address
* \param [in] buffer Buffer containing the new register's values
* \param [in] size Number of registers to be written
*/
void ( *WriteRegisters )( uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
*
* \param [in] addr First Radio register address
* \param [out] buffer Buffer where to copy the registers data
* \param [in] size Number of registers to be read
*/
void ( *ReadRegisters )( uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the maximum payload length.
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] max Maximum payload length in bytes
*/
void ( *SetMaxPayloadLength )( RadioModems_t modem, uint8_t max );
/*!
* \brief Sets the network to public or private. Updates the sync byte.
*
* \remark Applies to LoRa modem only
*
* \param [in] enable if true, it enables a public network
*/
void ( *SetPublicNetwork )( bool enable );
/*!
* \brief Gets the time required for the board plus radio to get out of sleep.[ms]
*
* \retval time Radio plus board wakeup time in ms.
*/
uint32_t ( *GetWakeupTime )( void );
/*!
* \brief Process radio irq
*/
void ( *IrqProcess )( void );
/*!
* \brief Sets the radio in reception mode with Max LNA gain for the given time
*
* \param [in] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
void ( *RxBoosted )( uint32_t timeout );
/*!
* \brief Sets the Rx duty cycle management parameters
*
* \param [in] rxTime Structure describing reception timeout value
* \param [in] sleepTime Structure describing sleep timeout value
*/
void ( *SetRxDutyCycle )( uint32_t rxTime, uint32_t sleepTime );
/*!
* @brief Sets the Transmitter in continuous PRBS mode
*
* \remark power and datarate shall be configured prior calling TxPrbs
*/
void ( *TxPrbs )( void );
/*!
* \brief Sets the Transmitter in continuous un-modulated Carrier mode at power dBm
*
* \param [in] power Tx power in dBm
*/
void ( *TxCw )( int8_t power );
/*!
* \brief Sets the reception parameters
*
* \param [in] modem Radio modem to be used [GENERIC_FSK or GENERIC_FSK]
* \param [in] config configuration of receiver
* fsk field to be used if modem =GENERIC_FSK
* lora field to be used if modem =GENERIC_LORA
* \param [in] rxContinuous Sets the reception in continuous mode
* [0: single mode, otherwise continuous mode]
* \param [in] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \return 0 when no parameters error, -1 otherwise
*/
int32_t ( *RadioSetRxGenericConfig )( GenericModems_t modem, RxConfigGeneric_t* config, uint32_t rxContinuous, uint32_t symbTimeout );
/*!
* \brief Sets the transmission parameters
*
* \param [in] modem Radio modem to be used [GENERIC_FSK or GENERIC_FSK or GENERIC_BPSK]
* \param [in] config configuration of receiver
* fsk field to be used if modem =GENERIC_FSK
* lora field to be used if modem =GENERIC_LORA
* bpsk field to be used if modem =GENERIC_BPSK
* \param [in] power Sets the output power [dBm]
* \param [in] timeout Reception timeout [ms]
* \return 0 when no parameters error, -1 otherwise
*/
int32_t ( *RadioSetTxGenericConfig )( GenericModems_t modem, TxConfigGeneric_t* config, int8_t power, uint32_t timeout );
/*!
* \brief Starts sending long Packet, packet maybe short
*
* \param [in] payload_size total payload size to be sent
* \param [in] timeout in ms
* \param [in] TxLongPacketGetNextChunkCb callback to be implemented on user side to feed partial chunk
* buffer: source buffer allocated by the app
* size: size in bytes to feed
* \return 0 when no parameters error, -1 otherwise
*/
int32_t ( *TransmitLongPacket )( uint16_t payload_size, uint32_t timeout,void (*TxLongPacketGetNextChunkCb) ( uint8_t** buffer, uint8_t buffer_size ) );
/*!
* \brief Starts receiving long Packet, packet maybe short
*
* \param [in] boosted_mode boosted_mode: 0 normal Rx, 1:improved sensitivity
* \param [in] timeout Reception timeout [ms]
* \param [in] RxLongStorePacketChunkCb callback to be implemented on user side to record partial chunk in the application
* buffer: source buffer allocated in the radio driver
* size: size in bytes to record
* \return 0 when no parameters error, -1 otherwise
*/
int32_t ( *ReceiveLongPacket )( uint8_t boosted_mode, uint32_t timeout, void (*RxLongStorePacketChunkCb) ( uint8_t* buffer, uint8_t chunk_size ) );
/* LrFhss extended radio functions */
/*!
* \brief Configure the radio LR-FHSS modem parameters
*
* \param [in] cfg_params LR-FHSS modem configuration parameters
*
* \returns Operation status
*/
radio_status_t ( *LrFhssSetCfg)( const radio_lr_fhss_cfg_params_t *cfg_params );
/*!
* \brief Get the time on air in millisecond for LR-FHSS packet
*
* \param [in] params Pointer to LR-FHSS time on air parameters
* \param [out] time_on_air_in_ms time on air parameters results in ms
*
* \returns Time-on-air value in ms for LR-FHSS packet LrFhssGetTimeOnAirInMs
*/
radio_status_t ( *LrFhssGetTimeOnAirInMs)( const radio_lr_fhss_time_on_air_params_t *params, uint32_t *time_on_air_in_ms );
};
/*!
* \brief Radio driver
*
* \remark This variable is defined and initialized in the specific radio
* board implementation
*/
extern const struct Radio_s Radio;
#ifdef __cplusplus
}
#endif
#endif // __RADIO_H__

View File

@@ -0,0 +1,123 @@
/*!
* \file radio_def.h
*
* \brief Radio driver API definition type definition
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*/
/*!
******************************************************************************
*
* Portions COPYRIGHT 2020 STMicroelectronics
*
* @file radio_def.h
* @author MCD Application Team
* @brief Radio driver API definition
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __RADIO_DEF_H__
#define __RADIO_DEF_H__
#ifdef __cplusplus
extern "C"
{
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
/* Public typedef -----------------------------------------------------------*/
/*!
* API return status
*/
typedef enum radio_status_e
{
RADIO_STATUS_OK,
RADIO_STATUS_UNSUPPORTED_FEATURE,
RADIO_STATUS_UNKNOWN_VALUE,
RADIO_STATUS_ERROR,
} radio_status_t;
/*!
* Radio driver supported modems
*/
typedef enum
{
MODEM_FSK = 0,
MODEM_LORA,
MODEM_MSK,
MODEM_BPSK,
MODEM_SIGFOX_TX,
MODEM_SIGFOX_RX,
}RadioModems_t;
/*!
* \brief Radio driver callback functions
*/
typedef struct
{
/*!
* \brief Tx Done callback prototype.
*/
void ( *TxDone )( void );
/*!
* \brief Tx Timeout callback prototype.
*/
void ( *TxTimeout )( void );
/*!
* \brief Rx Done callback prototype.
*
* \param [in] payload Received buffer pointer
* \param [in] size Received buffer size
* \param [in] rssi RSSI value computed while receiving the frame [dBm]
* \param [in] LoraSnr_FskCfo
* FSK : Carrier Frequency Offset in kHz
* LoRa: SNR value in dB
*/
void ( *RxDone )( uint8_t *payload, uint16_t size, int16_t rssi, int8_t LoraSnr_FskCfo );
/*!
* \brief Rx Timeout callback prototype.
*/
void ( *RxTimeout )( void );
/*!
* \brief Rx Error callback prototype.
*/
void ( *RxError )( void );
/*!
* \brief FHSS Change Channel callback prototype.
*
* \param [in] currentChannel Index number of the current channel
*/
void ( *FhssChangeChannel )( uint8_t currentChannel );
/*!
* \brief CAD Done callback prototype.
*
* \param [in] channelDetected Channel Activity detected during the CAD
*/
void ( *CadDone ) ( bool channelActivityDetected );
}RadioEvents_t;
#ifdef __cplusplus
}
#endif
#endif // __RADIO_DEF_H__

View File

@@ -0,0 +1,314 @@
/**
******************************************************************************
* @file radio_ex.h
* @author MCD Application Team
* @brief Extends radio capabilities (whitening, long packet)
******************************************************************************
* @attention
*
* Copyright (c) 2020(-2021) 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.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __RADIO_EX_H__
#define __RADIO_EX_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
/*******************************************Radio LORA enum*****************************************/
typedef enum
{
GENERIC_FSK = 0,
GENERIC_LORA,
GENERIC_BPSK, /*Tx only. In this mode, only payload is generated at the antenna (e.g. preamble nor syncword is generated and must be placed into the payload*/
GENERIC_MSK, /*Tx only. For Rx, FSK must be used*/
}GenericModems_t;
/*!
* @brief Represents the possible spreading factor values in LoRa packet types
*/
typedef enum
{
RADIO_LORA_SF5 = 0x05,
RADIO_LORA_SF6 = 0x06,
RADIO_LORA_SF7 = 0x07,
RADIO_LORA_SF8 = 0x08,
RADIO_LORA_SF9 = 0x09,
RADIO_LORA_SF10 = 0x0A,
RADIO_LORA_SF11 = 0x0B,
RADIO_LORA_SF12 = 0x0C,
}RADIO_LoRaSpreadingFactors_t;
/*!
* @brief Represents the coding rate values for LoRa packet type
*/
typedef enum
{
RADIO_LORA_CR_4_5 = 0x01,
RADIO_LORA_CR_4_6 = 0x02,
RADIO_LORA_CR_4_7 = 0x03,
RADIO_LORA_CR_4_8 = 0x04,
}RADIO_LoRaCodingRates_t;
/*!
* @brief Represents the bandwidth values for LoRa packet type
*/
typedef enum
{
RADIO_LORA_BW_500 = 6,
RADIO_LORA_BW_250 = 5,
RADIO_LORA_BW_125 = 4,
RADIO_LORA_BW_062 = 3,
RADIO_LORA_BW_041 = 10,
RADIO_LORA_BW_031 = 2,
RADIO_LORA_BW_020 = 9,
RADIO_LORA_BW_015 = 1,
RADIO_LORA_BW_010 = 8,
RADIO_LORA_BW_007 = 0,
}RADIO_LoRaBandwidths_t;
/*!
* @brief Holds the lengths mode of a LoRa packet type
*/
typedef enum
{
RADIO_LORA_PACKET_VARIABLE_LENGTH = 0x00, //!< The packet is on variable size, header included
RADIO_LORA_PACKET_FIXED_LENGTH = 0x01, //!< The packet is known on both sides, no header included in the packet
RADIO_LORA_PACKET_EXPLICIT = RADIO_LORA_PACKET_VARIABLE_LENGTH,
RADIO_LORA_PACKET_IMPLICIT = RADIO_LORA_PACKET_FIXED_LENGTH,
}RADIO_LoRaPacketLengthsMode_t;
/*!
* @brief Represents the CRC mode for LoRa packet type
*/
typedef enum
{
RADIO_LORA_CRC_ON = 0x01, //!< CRC activated
RADIO_LORA_CRC_OFF = 0x00, //!< CRC not used
}RADIO_LoRaCrcModes_t;
/*!
* @brief Represents the IQ mode for LoRa packet type
*/
typedef enum
{
RADIO_LORA_IQ_NORMAL = 0x00,
RADIO_LORA_IQ_INVERTED = 0x01,
}RADIO_LoRaIQModes_t;
/*!
* @brief Represents the IQ mode for LoRa packet type
*/
typedef enum
{
RADIO_LORA_LOWDR_OPT_OFF = 0x00, /*Forced to 0*/
RADIO_LORA_LOWDR_OPT_ON = 0x01, /*Forced to 1*/
RADIO_LORA_LOWDR_OPT_AUTO = 0x02, /*Forced to 1 when SF11 or SF12, 0 otherwise*/
}RADIO_Ld_Opt_t;
/*******************************************Radio FSK enum*****************************************/
/*!
* @brief Represents the modulation shaping parameter
*/
typedef enum
{
RADIO_FSK_MOD_SHAPING_OFF = 0x00,
RADIO_FSK_MOD_SHAPING_G_BT_03 = 0x08,
RADIO_FSK_MOD_SHAPING_G_BT_05 = 0x09,
RADIO_FSK_MOD_SHAPING_G_BT_07 = 0x0A,
RADIO_FSK_MOD_SHAPING_G_BT_1 = 0x0B,
}RADIO_FSK_ModShapings_t;
/*!
* @brief Represents the preamble length used to detect the packet on Rx side
*/
typedef enum
{
RADIO_FSK_PREAMBLE_DETECTOR_OFF = 0x00, //!< Preamble detection length off
RADIO_FSK_PREAMBLE_DETECTOR_08_BITS = 0x04, //!< Preamble detection length 8 bits
RADIO_FSK_PREAMBLE_DETECTOR_16_BITS = 0x05, //!< Preamble detection length 16 bits
RADIO_FSK_PREAMBLE_DETECTOR_24_BITS = 0x06, //!< Preamble detection length 24 bits
RADIO_FSK_PREAMBLE_DETECTOR_32_BITS = 0x07, //!< Preamble detection length 32 bit
}RADIO_FSK_PreambleDetection_t;
/*!
* @brief Represents the possible combinations of SyncWord correlators activated
*/
typedef enum
{
RADIO_FSK_ADDRESSCOMP_FILT_OFF = 0x00, //!< No correlator turned on, i.e. do not search for SyncWord
RADIO_FSK_ADDRESSCOMP_FILT_NODE = 0x01,
RADIO_FSK_ADDRESSCOMP_FILT_NODE_BROAD = 0x02,
}RADIO_FSK_AddressComp_t;
/*!
* @brief Radio packet length mode
*/
typedef enum
{
RADIO_FSK_PACKET_FIXED_LENGTH = 0x00, //!< The packet is known on both sides, no header included in the packet
RADIO_FSK_PACKET_VARIABLE_LENGTH = 0x01, //!< 1 byte packet length field inserted after the sync word*/
RADIO_FSK_PACKET_2BYTES_LENGTH = 0x02 //!< 2 bytes packet length field inserted after the sync word, payload size greater than 255 bytes */
}RADIO_FSK_PacketLengthModes_t;
/*!
* @brief Represents the CRC length
*/
typedef enum
{
RADIO_FSK_CRC_OFF = 0x01, //!< No CRC in use
RADIO_FSK_CRC_1_BYTES = 0x00,
RADIO_FSK_CRC_2_BYTES = 0x02,
RADIO_FSK_CRC_1_BYTES_INV = 0x04,
RADIO_FSK_CRC_2_BYTES_INV = 0x06,
RADIO_FSK_CRC_2_BYTES_IBM = 0xF1,
RADIO_FSK_CRC_2_BYTES_CCIT = 0xF2,
}RADIO_FSK_CrcTypes_t;
/*!
* @brief Radio whitening mode Off, CCIT or ibm
*/
typedef enum
{
RADIO_FSK_DC_FREE_OFF = 0x00, /*whitening Off*/
RADIO_FSK_DC_FREEWHITENING = 0x01, /*whitening CCIT*/
RADIO_FSK_DC_IBM_WHITENING = 0x02, /*whitening IBM*/
}RADIO_FSK_DcFree_t;
/*!
* @brief Radio Lora generic Rx parameters
*/
typedef struct
{
uint32_t StopTimerOnPreambleDetect; /*0 inactive, otherwise active*/
RADIO_LoRaSpreadingFactors_t SpreadingFactor;
RADIO_LoRaBandwidths_t Bandwidth;
RADIO_LoRaCodingRates_t Coderate;
RADIO_Ld_Opt_t LowDatarateOptimize;/*0 inactive, 1 active, otherwise auto (active for SF11 and SF12)*/
uint16_t PreambleLen;
RADIO_LoRaPacketLengthsMode_t LengthMode;
uint8_t MaxPayloadLength;
RADIO_LoRaCrcModes_t CrcMode;
RADIO_LoRaIQModes_t IqInverted;
} generic_param_rx_lora_t;
/*!
* @brief Radio FSK generic Rx parameters
*/
typedef struct
{
uint32_t StopTimerOnPreambleDetect;
uint32_t Bandwidth;
uint32_t BitRate; /* BitRate */
uint32_t PreambleLen; /* Preamble length in Byte */
uint8_t* SyncWord; /* SyncWord Buffer, 8 bytes max */
uint32_t MaxPayloadLength; /* maximum Payload length to listen */
uint16_t CrcPolynomial; /* Polynomial of the Crc*/
uint16_t CrcSeed; /* Seed of the Crc*/
uint16_t whiteSeed; /* WhiteningSeed, whitening can also be disabled by setting this field to 0 */
uint8_t SyncWordLength; /* SyncWord Buffer length in Byte*/
RADIO_FSK_PreambleDetection_t PreambleMinDetect;
RADIO_FSK_ModShapings_t ModulationShaping;
RADIO_FSK_AddressComp_t AddrComp;
RADIO_FSK_PacketLengthModes_t LengthMode; /* If the header is explicit, it will be transmitted in the GFSK packet. If the header is implicit, it will not be transmitted */
RADIO_FSK_CrcTypes_t CrcLength; /* Size of the CRC block in the GFSK packet */
RADIO_FSK_DcFree_t Whitening; /* whitening type*/
} generic_param_rx_fsk_t;
/*!
* @brief Radio generic Rx Configuration
*/
typedef struct
{
generic_param_rx_fsk_t fsk;
generic_param_rx_lora_t lora;
} RxConfigGeneric_t;
/*!
* @brief Radio BPSK generic Tx parameters
*/
typedef struct
{
uint32_t BitRate; /*BitRate*/
} generic_param_tx_bpsk_t;
/*!
* @brief Radio Lora generic Tx parameters
*/
typedef struct
{
RADIO_LoRaSpreadingFactors_t SpreadingFactor;
RADIO_LoRaBandwidths_t Bandwidth;
RADIO_LoRaCodingRates_t Coderate;
RADIO_Ld_Opt_t LowDatarateOptimize; /*0 inactive, otherwise active*/
uint16_t PreambleLen;
RADIO_LoRaPacketLengthsMode_t LengthMode;
RADIO_LoRaCrcModes_t CrcMode;
RADIO_LoRaIQModes_t IqInverted;
} generic_param_tx_lora_t;
/*!
* @brief Radio FSK generic Tx parameters
*/
typedef struct
{
uint32_t BitRate; /* BitRate */
uint32_t PreambleLen; /* in Byte */
uint8_t* SyncWord; /* SyncWord Buffer, 8 bytes max */
uint16_t CrcPolynomial;
uint16_t CrcSeed;
uint16_t whiteSeed; /* Whitening seed, whitening can be disabled by setting this field to 0 */
uint8_t SyncWordLength; /* in Byte */
RADIO_FSK_ModShapings_t ModulationShaping;
RADIO_FSK_PacketLengthModes_t HeaderType; /* If the header is explicit, it will be transmitted in the GFSK packet. If the header is implicit, it will not be transmitted */
RADIO_FSK_CrcTypes_t CrcLength; /* Size of the CRC block in the GFSK packet */
RADIO_FSK_DcFree_t Whitening;
uint32_t FrequencyDeviation; /* FrequencyDeviation */
} generic_param_tx_fsk_t;
/*!
* @brief Radio MSK generic Tx parameters
*/
typedef struct
{
uint32_t BitRate; /* BitRate */
uint32_t PreambleLen; /* in Byte */
uint8_t* SyncWord; /* SyncWord Buffer, 8 bytes max */
uint16_t CrcPolynomial;
uint16_t CrcSeed;
uint16_t whiteSeed; /* Whitening seed, whitening can be disabled by setting this field to 0 */
uint8_t SyncWordLength; /* in Byte */
RADIO_FSK_ModShapings_t ModulationShaping;
RADIO_FSK_PacketLengthModes_t HeaderType; /* If the header is explicit, it will be transmitted in the GFSK packet. If the header is implicit, it will not be transmitted */
RADIO_FSK_CrcTypes_t CrcLength; /* Size of the CRC block in the GFSK packet */
RADIO_FSK_DcFree_t Whitening;
} generic_param_tx_msk_t;
/*!
* @brief Radio generic Tx Configuration
*/
typedef union
{
generic_param_tx_fsk_t fsk;
generic_param_tx_lora_t lora;
generic_param_tx_bpsk_t bpsk;
generic_param_tx_msk_t msk;
} TxConfigGeneric_t;
#ifdef __cplusplus
}
#endif
#endif // __RADIO_EX_H__

View File

@@ -0,0 +1,862 @@
/*!
* @file lr_fhss_mac.c
*
* @brief Radio-independent LR-FHSS driver implementation
*
* The Clear BSD License
* Copyright Semtech Corporation 2021. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) 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 Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. 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 SEMTECH CORPORATION 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.
*/
/*
* -----------------------------------------------------------------------------
* --- DEPENDENCIES ------------------------------------------------------------
*/
#include "lr_fhss_mac.h"
#include <string.h>
/*
* -----------------------------------------------------------------------------
* --- PRIVATE MACROS-----------------------------------------------------------
*/
#ifdef TEST
#define STATIC
#else
#define STATIC static
#endif
/*
* -----------------------------------------------------------------------------
* --- PRIVATE CONSTANTS -------------------------------------------------------
*/
#define LR_FHSS_MAX_TMP_BUF_BYTES ( 608 )
/*
* -----------------------------------------------------------------------------
* --- PRIVATE TYPES -----------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PRIVATE VARIABLES -------------------------------------------------------
*/
/** @brief Channel count as function of bandwidth index, from Table 9 specification v18 */
STATIC const uint16_t lr_fhss_channel_count[] = { 80, 176, 280, 376, 688, 792, 1480, 1584, 3120, 3224 };
/** @brief Generating polynomial as function of polynomial index, n_grid in { 10, 22, 28, 30, 35, 47 } */
STATIC const uint8_t lr_fhss_lfsr_poly1[] = { 33, 45, 48, 51, 54, 57 };
/** @brief Generating polynomial as function of polynomial index, n_grid in { 86, 99 } */
STATIC const uint8_t lr_fhss_lfsr_poly2[] = { 65, 68, 71, 72 };
/** @brief Generating polynomial as function of polynomial index, n_grid in { 185, 198 } */
STATIC const uint8_t lr_fhss_lfsr_poly3[] = { 142, 149 };
/** @brief used for 1/3 rate viterbi encoding */
STATIC const uint8_t lr_fhss_viterbi_1_3_table[64][2] =
{
{ 0, 7 }, { 3, 4 }, { 7, 0 }, { 4, 3 }, { 6, 1 }, { 5, 2 }, { 1, 6 }, { 2, 5 }, { 1, 6 }, { 2, 5 }, { 6, 1 },
{ 5, 2 }, { 7, 0 }, { 4, 3 }, { 0, 7 }, { 3, 4 }, { 4, 3 }, { 7, 0 }, { 3, 4 }, { 0, 7 }, { 2, 5 }, { 1, 6 },
{ 5, 2 }, { 6, 1 }, { 5, 2 }, { 6, 1 }, { 2, 5 }, { 1, 6 }, { 3, 4 }, { 0, 7 }, { 4, 3 }, { 7, 0 }, { 7, 0 },
{ 4, 3 }, { 0, 7 }, { 3, 4 }, { 1, 6 }, { 2, 5 }, { 6, 1 }, { 5, 2 }, { 6, 1 }, { 5, 2 }, { 1, 6 }, { 2, 5 },
{ 0, 7 }, { 3, 4 }, { 7, 0 }, { 4, 3 }, { 3, 4 }, { 0, 7 }, { 4, 3 }, { 7, 0 }, { 5, 2 }, { 6, 1 }, { 2, 5 },
{ 1, 6 }, { 2, 5 }, { 1, 6 }, { 5, 2 }, { 6, 1 }, { 4, 3 }, { 7, 0 }, { 3, 4 }, { 0, 7 }
};
/** @brief used for 1/2 rate viterbi encoding */
STATIC const uint8_t lr_fhss_viterbi_1_2_table[16][2] =
{
{ 0, 3 }, { 1, 2 }, { 2, 1 }, { 3, 0 }, { 2, 1 }, { 3, 0 },
{ 0, 3 }, { 1, 2 }, { 3, 0 }, { 2, 1 }, { 1, 2 }, { 0, 3 },
{ 1, 2 }, { 0, 3 }, { 3, 0 }, { 2, 1 }
};
/** @brief used header interleaving */
STATIC const uint8_t lr_fhss_header_interleaver_minus_one[80] =
{
0, 18, 36, 54, 72, 4, 22, 40, //
58, 76, 8, 26, 44, 62, 12, 30, //
48, 66, 16, 34, 52, 70, 1, 19, //
37, 55, 73, 5, 23, 41, 59, 77, //
9, 27, 45, 63, 13, 31, 49, 67, //
17, 35, 53, 71, 2, 20, 38, 56, //
74, 6, 24, 42, 60, 78, 10, 28, //
46, 64, 14, 32, 50, 68, 3, 21, //
39, 57, 75, 7, 25, 43, 61, 79, //
11, 29, 47, 65, 15, 33, 51, 69 //
};
/** @brief lookup table for lr_fhss_header_crc8 */
const uint8_t lr_fhss_header_crc8_lut[256] =
{
0, 47, 94, 113, 188, 147, 226, 205, 87, 120, 9, 38, 235, 196, 181, 154, //
174, 129, 240, 223, 18, 61, 76, 99, 249, 214, 167, 136, 69, 106, 27, 52, //
115, 92, 45, 2, 207, 224, 145, 190, 36, 11, 122, 85, 152, 183, 198, 233, //
221, 242, 131, 172, 97, 78, 63, 16, 138, 165, 212, 251, 54, 25, 104, 71, //
230, 201, 184, 151, 90, 117, 4, 43, 177, 158, 239, 192, 13, 34, 83, 124, //
72, 103, 22, 57, 244, 219, 170, 133, 31, 48, 65, 110, 163, 140, 253, 210, //
149, 186, 203, 228, 41, 6, 119, 88, 194, 237, 156, 179, 126, 81, 32, 15, //
59, 20, 101, 74, 135, 168, 217, 246, 108, 67, 50, 29, 208, 255, 142, 161, //
227, 204, 189, 146, 95, 112, 1, 46, 180, 155, 234, 197, 8, 39, 86, 121, //
77, 98, 19, 60, 241, 222, 175, 128, 26, 53, 68, 107, 166, 137, 248, 215, //
144, 191, 206, 225, 44, 3, 114, 93, 199, 232, 153, 182, 123, 84, 37, 10, //
62, 17, 96, 79, 130, 173, 220, 243, 105, 70, 55, 24, 213, 250, 139, 164, //
5, 42, 91, 116, 185, 150, 231, 200, 82, 125, 12, 35, 238, 193, 176, 159, //
171, 132, 245, 218, 23, 56, 73, 102, 252, 211, 162, 141, 64, 111, 30, 49, //
118, 89, 40, 7, 202, 229, 148, 187, 33, 14, 127, 80, 157, 178, 195, 236, //
216, 247, 134, 169, 100, 75, 58, 21, 143, 160, 209, 254, 51, 28, 109, 66 //
};
/** @brief lookup table for lr_fhss_payload_crc16 */
const uint16_t lr_fhss_payload_crc16_lut[256] =
{
0, 30043, 60086, 40941, 41015, 54636, 19073, 16346, 13621, 16494, 57219, 43736, 38146, 57433, 32692, 2799, //
27242, 7985, 32988, 62855, 51805, 48902, 8427, 21936, 24415, 10756, 46569, 49330, 65384, 35379, 5598, 24709, //
54484, 41359, 15970, 19257, 29923, 440, 40533, 60174, 57825, 38074, 2903, 32268, 16854, 13453, 43872, 56891, //
48830, 52197, 21512, 8531, 7817, 27602, 62527, 33124, 35723, 65232, 24893, 5222, 11196, 24295, 49418, 46161, //
56563, 43432, 13893, 17182, 31940, 2463, 38514, 58153, 59846, 40093, 880, 30251, 18929, 15530, 41799, 54812, //
46745, 50114, 23599, 10612, 5806, 25589, 64536, 35139, 33708, 63223, 26906, 7233, 9115, 22208, 51501, 48246, //
2087, 32124, 58001, 38858, 43024, 56651, 17062, 14333, 15634, 18505, 55204, 41727, 40229, 59518, 30611, 712, //
25165, 5910, 35067, 64928, 49786, 46881, 10444, 23959, 22392, 8739, 48590, 51349, 63311, 33300, 7673, 26786, //
52413, 47590, 9739, 21328, 27786, 6609, 34364, 62311, 63880, 36051, 4926, 26213, 22975, 11492, 45833, 50770, //
42711, 54156, 19553, 14650, 1760, 29627, 60502, 39181, 37858, 59065, 31060, 3087, 13269, 18062, 55651, 44088, //
6249, 27954, 62175, 34692, 47198, 52485, 21224, 10163, 11612, 22535, 51178, 45745, 36203, 63536, 26589, 4742, //
29187, 1880, 39093, 60910, 53812, 42863, 14466, 19929, 18230, 12909, 44416, 55515, 59137, 37466, 3511, 30956, //
4174, 25877, 64248, 36771, 45177, 50466, 23247, 12180, 9595, 20512, 53197, 47766, 34124, 61463, 28666, 6817, //
31268, 3967, 37010, 58825, 55827, 44872, 12453, 17918, 20241, 14922, 42407, 53500, 61222, 39549, 1424, 28875, //
50330, 45505, 11820, 23415, 25773, 4598, 36379, 64320, 61871, 34036, 6937, 28226, 20888, 9411, 47918, 52853, //
44784, 56235, 17478, 12573, 3783, 31644, 58481, 37162, 39877, 61086, 29043, 1064, 15346, 20137, 53572, 42015
};
/*!
* @brief integral square root, rounded up
*
* @param [in] x argument
*
* @returns Square root of argument, rounded up to next integer
*
* @remark This function is only appropriate to use for reasonably small arguments
*/
STATIC uint16_t sqrt_uint16( uint16_t x );
/*
* -----------------------------------------------------------------------------
* --- PRIVATE FUNCTION DECLARATIONS -------------------------------------------
*/
/*!
* @brief Compute 16-bit payload CRC
*
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bytecount Input buffer length, in bytes
*
* @returns 16-bit CRC
*/
STATIC uint16_t lr_fhss_payload_crc16( const uint8_t *data_in, uint16_t data_in_bytecount );
/*!
* @brief Compute 8-bit header CRC
*
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bytecount Input buffer length, in bytes
*
* @returns 8-bit CRC
*/
STATIC uint8_t lr_fhss_header_crc8( const uint8_t *data_in, uint16_t data_in_bytecount );
/*!
* @brief Whiten the payload
*
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bytecount Input buffer length, in bytes
* @param [out] data_out Pointer to output buffer, of same length as input buffer
*/
STATIC void lr_fhss_payload_whitening( const uint8_t *data_in, uint16_t data_in_bytecount, uint8_t *data_out );
/*!
* @brief Extract specific bit from array of bytes
*
* @param [in] data_in Array of bytes
* @param [in] bit_number Index of bit in array
*
* @returns Value of the bit
*/
STATIC uint8_t lr_fhss_extract_bit_in_byte_vector( const uint8_t *data_in, uint32_t bit_number );
/*!
* @brief Set specific bit in array of bytes
*
* @param [in] data_in Array of bytes
* @param [in] bit_number Index of bit in array
* @param [in] bit_value Value to be set
*/
STATIC void lr_fhss_set_bit_in_byte_vector( uint8_t *vector, uint32_t bit_number, uint8_t bit_value );
/*!
* @brief Compute 1/2 rate Viterbi encoding
*
* @param [in,out] encod_state Pointer to encoded state
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bitcount Length of input buffer, in bits
* @param [in] data_out Pointer to output buffer
*
* @returns Length of output buffer, in bits
*/
STATIC uint16_t lr_fhss_convolution_encode_viterbi_1_2_base( uint8_t *encod_state, const uint8_t *data_in,
uint16_t data_in_bitcount, uint8_t *data_out );
/*!
* @brief Compute 1/3 rate Viterbi encoding
*
* @param [in,out] encod_state Pointer to encoded state
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bitcount Length of input buffer, in bits
* @param [out] data_out Pointer to output buffer
*
* @returns Length of output buffer, in bits
*/
STATIC uint16_t lr_fhss_convolution_encode_viterbi_1_3_base( uint8_t *encod_state, const uint8_t *data_in,
uint16_t data_in_bitcount, uint8_t *data_out );
/*!
* @brief Convolute using lr_fhss_convolution_encode_viterbi_1_2_base with optional tail-biting
*
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bitcount Length of input buffer, in bits
* @param [in] tail_biting Set to true to activate tail-biting
* @param [out] data_out Pointer to output buffer
*
* @remark If tail-biting is activated, this function calls lr_fhss_convolution_encode_viterbi_1_2_base twice
*
* @returns Length of output buffer, in bits
*/
STATIC uint16_t lr_fhss_convolution_encode_viterbi_1_2( const uint8_t *data_in, uint16_t data_in_bitcount,
bool tail_biting, uint8_t *data_out );
/*!
* @brief Convolute using lr_fhss_convolution_encode_viterbi_1_3_base
*
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bitcount Length of input buffer, in bits
* @param [out] data_out Pointer to output buffer
*
* @returns Length of output buffer, in bits
*/
STATIC uint16_t lr_fhss_convolution_encode_viterbi_1_3( const uint8_t *data_in, uint16_t data_in_bitcount,
uint8_t *data_out );
/*!
* @brief Computes payload interleaving
*
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bitcount Length of input buffer, in bits
* @param [out] data_out Pointer to output buffer
* @param [in] output_offset Output offset indicating where data must be placed, in bits, relative to data_out bit 0
*
* @returns Length of output buffer, in bits
*/
STATIC uint16_t lr_fhss_payload_interleaving( const uint8_t *data_in, uint16_t data_in_bitcount, uint8_t *data_out,
uint32_t output_offset );
/*!
* @brief Create the raw LR-FHSS header
*
* @param [in] params Parameter structure
* @param [in] hop_sequence_id The hop sequence ID that will be used to obtain hop-related data
* @param [in] payload_length Length of application payload, in bytes
* @param [out] data_out Pointer to output buffer
*/
STATIC void lr_fhss_raw_header( const lr_fhss_v1_params_t *params, uint16_t hop_sequence_id, uint16_t payload_length,
uint8_t *data_out );
/*!
* @brief Store sync word index inside provided header
*
* @param [in] sync_word_index The sync word index to store
* @param [out] data_out Pointer to output buffer
*/
STATIC void lr_fhss_store_header_sync_word_index( uint8_t sync_word_index, uint8_t *data_out );
/*!
* @brief Get the bit count and block count for a LR-FHSS frame
*
* @param [in] params Parameter structure
* @param [in] payload_length Length of physical payload, in bytes
* @param [out] nb_hops_out Number of LR-FHSS hops
*
* @returns Length of physical payload, in bits
*/
STATIC uint16_t lr_fhss_get_bit_and_hop_count( const lr_fhss_v1_params_t *params, uint16_t payload_length,
uint8_t *nb_hops_out );
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTION DEFINITIONS ---------------------------------------------
*/
unsigned int lr_fhss_get_hop_sequence_count( const lr_fhss_v1_params_t *params )
{
if( ( params->grid == LR_FHSS_V1_GRID_25391_HZ ) ||
( ( params->grid == LR_FHSS_V1_GRID_3906_HZ ) && ( params->bw < LR_FHSS_V1_BW_335938_HZ ) ) )
{
return 384;
}
return 512;
}
void lr_fhss_process_parameters( const lr_fhss_v1_params_t *params, uint16_t payload_length, lr_fhss_digest_t *digest )
{
digest->nb_bits = lr_fhss_get_bit_and_hop_count( params, payload_length, &digest->nb_hops );
digest->nb_bytes = ( digest->nb_bits + 8 - 1 ) / 8;
if( params->enable_hopping )
{
digest->nb_hops = digest->nb_hops;
}
else
{
digest->nb_hops = 1;
}
}
radio_status_t lr_fhss_get_hop_params( const lr_fhss_v1_params_t *params, lr_fhss_hop_params_t *hop_params,
uint16_t *initial_state, uint16_t hop_sequence_id )
{
uint32_t channel_count = lr_fhss_channel_count[params->bw];
if( params->grid == LR_FHSS_V1_GRID_3906_HZ )
{
hop_params->n_grid = channel_count / 8;
}
else
{
hop_params->n_grid = channel_count / 52;
}
switch( hop_params->n_grid )
{
case 10:
case 22:
case 28:
case 30:
case 35:
case 47:
{
*initial_state = 6;
hop_params->polynomial = lr_fhss_lfsr_poly1[hop_sequence_id >> 6];
hop_params->xoring_seed = hop_sequence_id & 0x3F;
if( hop_sequence_id >= 384 )
{
return RADIO_STATUS_ERROR;
}
break;
}
case 60:
case 62:
{
*initial_state = 56;
hop_params->polynomial = lr_fhss_lfsr_poly1[hop_sequence_id >> 6];
hop_params->xoring_seed = hop_sequence_id & 0x3F;
if( hop_sequence_id >= 384 )
{
return RADIO_STATUS_ERROR;
}
break;
}
case 86:
case 99:
{
*initial_state = 6;
hop_params->polynomial = lr_fhss_lfsr_poly2[hop_sequence_id >> 7];
hop_params->xoring_seed = hop_sequence_id & 0x7F;
break;
}
case 185:
case 198:
{
*initial_state = 6;
hop_params->polynomial = lr_fhss_lfsr_poly3[hop_sequence_id >> 8];
hop_params->xoring_seed = hop_sequence_id & 0xFF;
break;
}
case 390:
case 403:
{
*initial_state = 6;
hop_params->polynomial = 264;
hop_params->xoring_seed = hop_sequence_id;
break;
}
default:
return RADIO_STATUS_ERROR;
}
hop_params->hop_sequence_id = hop_sequence_id;
return RADIO_STATUS_OK;
}
uint16_t lr_fhss_get_next_state( uint16_t *lfsr_state, const lr_fhss_hop_params_t *hop_params )
{
uint16_t hop;
do
{
uint16_t lsb = *lfsr_state & 1;
*lfsr_state >>= 1;
if( lsb )
{
*lfsr_state ^= hop_params->polynomial;
}
hop = hop_params->xoring_seed;
if( hop != *lfsr_state )
{
hop ^= *lfsr_state;
}
} while( hop > hop_params->n_grid );
return hop - 1;
}
int16_t lr_fhss_get_next_freq_in_grid( uint16_t *lfsr_state, const lr_fhss_hop_params_t *hop_params,
const lr_fhss_v1_params_t *params )
{
uint16_t n_i;
if( params->enable_hopping )
{
n_i = lr_fhss_get_next_state( lfsr_state, hop_params );
}
else
{
n_i = hop_params->hop_sequence_id % hop_params->n_grid;
}
if( n_i < ( hop_params->n_grid >> 1 ) )
{
return n_i;
}
else
{
return n_i - hop_params->n_grid;
}
}
/**************************** Build LR-FHSS Frame ***********************************************************
* Core of the LR-FHSS frame generator *
* *
* In |---------| |-----| |-----------------| |-------| |------------| |----------------------| Out *
**---|Whitening|--|CRC16|--|Outer Code + CRC8|--|Viterbi|--|Interleaving|--|Sync+header+crc Header|------ *
* |---------| |-----| |-----------------|--|-------| |------------| |----------------------| *
* *
**********************************************************************************************************/
uint16_t lr_fhss_build_frame( const lr_fhss_v1_params_t *params, uint16_t hop_sequence_id, const uint8_t *data_in,
uint16_t data_in_bytecount, uint8_t *data_out )
{
uint8_t data_out_tmp[LR_FHSS_MAX_TMP_BUF_BYTES] = { 0 };
lr_fhss_payload_whitening( data_in, data_in_bytecount, data_out );
uint16_t payload_crc = lr_fhss_payload_crc16( data_out, data_in_bytecount );
data_out[data_in_bytecount] = ( payload_crc >> 8 ) & 0xFF;
data_out[data_in_bytecount + 1] = payload_crc & 0xFF;
data_out[data_in_bytecount + 2] = 0;
// the 1/3 encoded bytes can go up to LR_FHSS_MAX_TMP_BUF_BYTES temporarily, before puncturing it
uint16_t nb_bits =
lr_fhss_convolution_encode_viterbi_1_3( data_out, 8 * ( data_in_bytecount + 2 ) + 6, data_out_tmp );
// Avoid putting random stack data into payload
memset( data_out, 0, LR_FHSS_MAX_PHY_PAYLOAD_BYTES );
if( params->cr != LR_FHSS_V1_CR_1_3 )
{
// this assumes first matrix values are always the same, which is the case
uint32_t matrix_index = 0;
uint8_t matrix[15] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 };
uint8_t matrix_len = 0;
switch( params->cr )
{
case LR_FHSS_V1_CR_5_6:
matrix_len = 15;
break;
case LR_FHSS_V1_CR_2_3:
matrix_len = 6;
break;
case LR_FHSS_V1_CR_1_2:
matrix_len = 3;
break;
default:
// LR_FHSS_V1_CR_1_3 is excluded from this code block
break;
}
uint32_t j = 0;
for( uint32_t i = 0; i < nb_bits; i++ )
{
if( matrix[matrix_index] )
{
lr_fhss_set_bit_in_byte_vector( data_out, j++, lr_fhss_extract_bit_in_byte_vector( data_out_tmp, i ) );
}
if( ++matrix_index == matrix_len )
{
matrix_index = 0;
}
}
nb_bits = j;
memcpy( data_out_tmp, data_out, ( nb_bits + 7 ) / 8 );
}
// Interleave directly to data_out
nb_bits =
lr_fhss_payload_interleaving( data_out_tmp, nb_bits, data_out, LR_FHSS_HEADER_BITS * params->header_count );
// Build the header
uint8_t raw_header[LR_FHSS_HALF_HDR_BYTES];
lr_fhss_raw_header( params, hop_sequence_id, data_in_bytecount, raw_header );
uint16_t header_offset = 0;
for( uint32_t i = 0; i < params->header_count; i++ )
{
// Insert appropriate index into header
lr_fhss_store_header_sync_word_index( params->header_count - i - 1, raw_header );
raw_header[4] = lr_fhss_header_crc8( raw_header, 4 );
// Convolutional encode
uint8_t coded_header[LR_FHSS_HDR_BYTES] = { 0 };
lr_fhss_convolution_encode_viterbi_1_2( raw_header, LR_FHSS_HALF_HDR_BITS, 1, coded_header );
// Header guard bits
lr_fhss_set_bit_in_byte_vector( data_out, header_offset + 0, 0 );
lr_fhss_set_bit_in_byte_vector( data_out, header_offset + 1, 0 );
// Interleave the header directly to the physical payload buffer
for( uint32_t j = 0; j < LR_FHSS_HALF_HDR_BITS; j++ )
{
lr_fhss_set_bit_in_byte_vector(
data_out, header_offset + 2 + j,
lr_fhss_extract_bit_in_byte_vector( coded_header, lr_fhss_header_interleaver_minus_one[j] ) );
}
for( uint32_t j = 0; j < LR_FHSS_HALF_HDR_BITS; j++ )
{
lr_fhss_set_bit_in_byte_vector(
data_out, header_offset + 2 + LR_FHSS_HALF_HDR_BITS + LR_FHSS_SYNC_WORD_BITS + j,
lr_fhss_extract_bit_in_byte_vector( coded_header,
lr_fhss_header_interleaver_minus_one[LR_FHSS_HALF_HDR_BITS + j] ) );
}
// Copy the sync word to the physical payload buffer
for( uint32_t j = 0; j < LR_FHSS_SYNC_WORD_BITS; j++ )
{
lr_fhss_set_bit_in_byte_vector( data_out, header_offset + 2 + LR_FHSS_HALF_HDR_BITS + j,
lr_fhss_extract_bit_in_byte_vector( params->sync_word, j ) );
}
header_offset += LR_FHSS_HEADER_BITS;
}
return ( header_offset + nb_bits + 7 ) / 8;
}
uint32_t lr_fhss_get_time_on_air_in_ms( const lr_fhss_v1_params_t *params, uint16_t payload_length )
{
// Multiply by 1000 / 488.28125, or equivalently 256/125, rounding up
return ( ( lr_fhss_get_time_on_air_numerator( params, payload_length ) << 8 ) + 124 ) / 125;
}
/*
* -----------------------------------------------------------------------------
* --- PRIVATE FUNCTION DEFINITIONS --------------------------------------------
*/
STATIC uint16_t lr_fhss_payload_crc16( const uint8_t *data_in, uint16_t data_in_bytecount )
{
uint16_t crc16 = 65535;
uint8_t pos = 0;
for( uint16_t k = 0; k < data_in_bytecount; k++ )
{
pos = ( ( crc16 >> 8 ) ^ data_in[k] );
crc16 = ( crc16 << 8 ) ^ lr_fhss_payload_crc16_lut[pos];
}
return crc16;
}
STATIC uint8_t lr_fhss_header_crc8( const uint8_t *data_in, uint16_t data_in_bytecount )
{
uint8_t crc8 = 255;
for( uint16_t k = 0; k < data_in_bytecount; k++ )
{
uint8_t pos = ( crc8 ^ data_in[k] );
crc8 = lr_fhss_header_crc8_lut[pos];
}
return crc8;
}
STATIC void lr_fhss_payload_whitening( const uint8_t *data_in, uint16_t data_in_bytecount, uint8_t *data_out )
{
uint8_t lfsr = 0xFF;
for( uint8_t index = 0; index < data_in_bytecount; index++ )
{
uint8_t u = data_in[index] ^ lfsr;
data_out[index] = ( ( u & 0x0F ) << 4 ) | ( ( u & 0xF0 ) >> 4 );
lfsr =
( lfsr << 1 ) | ( ( ( lfsr & 0x80 ) >> 7 ) ^
( ( ( lfsr & 0x20 ) >> 5 ) ^ ( ( ( lfsr & 0x10 ) >> 4 ) ^ ( ( lfsr & 0x8 ) >> 3 ) ) ) );
}
}
STATIC uint8_t lr_fhss_extract_bit_in_byte_vector( const uint8_t *data_in, uint32_t bit_number )
{
uint32_t index = bit_number >> 3;
uint8_t bit_pos = 7 - ( bit_number % 8 );
if( data_in[index] & ( 1 << bit_pos ) )
{
return 1;
}
return 0;
}
STATIC void lr_fhss_set_bit_in_byte_vector( uint8_t *vector, uint32_t bit_number, uint8_t bit_value )
{
uint32_t index = bit_number >> 3;
uint8_t bit_pos = 7 - ( bit_number % 8 );
vector[index] = ( vector[index] & ( 0xff - ( 1 << bit_pos ) ) ) | ( bit_value << bit_pos );
}
STATIC uint16_t lr_fhss_convolution_encode_viterbi_1_2_base( uint8_t *encod_state, const uint8_t *data_in,
uint16_t data_in_bitcount, uint8_t *data_out )
{
uint8_t g1g0;
uint8_t cur_bit;
uint16_t ind_bit;
uint16_t data_out_bitcount = 0;
uint16_t bin_out_16 = 0;
for( ind_bit = 0; ind_bit < data_in_bitcount; ind_bit++ )
{
cur_bit = lr_fhss_extract_bit_in_byte_vector( data_in, ind_bit );
g1g0 = lr_fhss_viterbi_1_2_table[*encod_state][cur_bit];
*encod_state = ( *encod_state * 2 + cur_bit ) % 16;
bin_out_16 |= ( g1g0 << ( ( 7 - ( ind_bit % 8 ) ) << 1 ) );
if( ind_bit % 8 == 7 )
{
*data_out++ = ( uint8_t )( bin_out_16 >> 8 );
*data_out++ = ( uint8_t ) bin_out_16;
bin_out_16 = 0;
}
data_out_bitcount += 2;
}
if( ind_bit % 8 )
{
*data_out++ = ( uint8_t )( bin_out_16 >> 8 );
*data_out++ = ( uint8_t ) bin_out_16;
bin_out_16 = 0;
}
return data_out_bitcount;
}
STATIC uint16_t lr_fhss_convolution_encode_viterbi_1_3_base( uint8_t *encod_state, const uint8_t *data_in,
uint16_t data_in_bitcount, uint8_t *data_out )
{
uint8_t g1g0;
uint8_t cur_bit;
uint16_t ind_bit;
uint16_t data_out_bitcount = 0;
uint32_t bin_out_32 = 0;
for( ind_bit = 0; ind_bit < data_in_bitcount; ind_bit++ )
{
cur_bit = lr_fhss_extract_bit_in_byte_vector( data_in, ind_bit );
g1g0 = lr_fhss_viterbi_1_3_table[*encod_state][cur_bit];
*encod_state = ( *encod_state * 2 + cur_bit ) % 64;
bin_out_32 |= ( g1g0 << ( ( 7 - ( ind_bit % 8 ) ) * 3 ) );
if( ind_bit % 8 == 7 )
{
*data_out++ = ( uint8_t )( bin_out_32 >> 16 );
*data_out++ = ( uint8_t )( bin_out_32 >> 8 );
*data_out++ = ( uint8_t ) bin_out_32;
bin_out_32 = 0;
}
data_out_bitcount += 3;
}
if( ind_bit % 8 )
{
*data_out++ = ( uint8_t )( bin_out_32 >> 16 );
*data_out++ = ( uint8_t )( bin_out_32 >> 8 );
*data_out++ = ( uint8_t ) bin_out_32;
bin_out_32 = 0;
}
return data_out_bitcount;
}
STATIC uint16_t lr_fhss_convolution_encode_viterbi_1_2( const uint8_t *data_in, uint16_t data_in_bitcount,
bool tail_biting, uint8_t *data_out )
{
uint8_t encode_state = 0;
uint16_t data_out_bitcount;
data_out_bitcount =
lr_fhss_convolution_encode_viterbi_1_2_base( &encode_state, data_in, data_in_bitcount, data_out );
if( tail_biting )
{
data_out_bitcount =
lr_fhss_convolution_encode_viterbi_1_2_base( &encode_state, data_in, data_in_bitcount, data_out );
}
return data_out_bitcount;
}
STATIC uint16_t lr_fhss_convolution_encode_viterbi_1_3( const uint8_t *data_in, uint16_t data_in_bitcount,
uint8_t *data_out )
{
uint8_t encode_state = 0;
return lr_fhss_convolution_encode_viterbi_1_3_base( &encode_state, data_in, data_in_bitcount, data_out );
}
STATIC uint16_t sqrt_uint16( uint16_t x )
{
uint16_t y = 0;
while( y * y < x )
{
y += 1;
}
return y;
}
STATIC uint16_t lr_fhss_payload_interleaving( const uint8_t *data_in, uint16_t data_in_bitcount, uint8_t *data_out,
uint32_t output_offset )
{
uint16_t step = sqrt_uint16( data_in_bitcount );
const uint16_t step_v = step >> 1;
step = step << 1;
uint16_t pos = 0;
uint16_t st_idx = 0;
uint16_t st_idx_init = 0;
int16_t bits_left = data_in_bitcount;
uint16_t out_row_index = output_offset;
while( bits_left > 0 )
{
int16_t in_row_width = bits_left;
if( in_row_width > LR_FHSS_FRAG_BITS )
{
in_row_width = LR_FHSS_FRAG_BITS;
}
lr_fhss_set_bit_in_byte_vector( data_out, 0 + out_row_index, 0 ); // guard bits
lr_fhss_set_bit_in_byte_vector( data_out, 1 + out_row_index, 0 ); // guard bits
for( uint32_t j = 0; j < in_row_width; j++ )
{
lr_fhss_set_bit_in_byte_vector( data_out, j + 2 + out_row_index,
lr_fhss_extract_bit_in_byte_vector( data_in, pos ) ); // guard bit
pos += step;
if( pos >= data_in_bitcount )
{
st_idx += step_v;
if( st_idx >= step )
{
st_idx_init++;
st_idx = st_idx_init;
}
pos = st_idx;
}
}
bits_left -= LR_FHSS_FRAG_BITS;
out_row_index += 2 + in_row_width;
}
return out_row_index - output_offset;
}
STATIC void lr_fhss_raw_header( const lr_fhss_v1_params_t *params, uint16_t hop_sequence_id, uint16_t payload_length,
uint8_t *data_out )
{
data_out[0] = payload_length;
data_out[1] = ( params->modulation_type << 5 ) + ( params->cr << 3 ) + ( params->grid << 2 ) +
( params->enable_hopping ? 2 : 0 ) + ( params->bw >> 3 );
data_out[2] = ( ( params->bw & 0x07 ) << 5 ) + ( hop_sequence_id >> 4 );
data_out[3] = ( ( hop_sequence_id & 0x000F ) << 4 );
}
STATIC void lr_fhss_store_header_sync_word_index( uint8_t sync_word_index, uint8_t *data_out )
{
data_out[3] = ( data_out[3] & ~0x0C ) | ( sync_word_index << 2 );
}
STATIC uint16_t lr_fhss_get_bit_and_hop_count( const lr_fhss_v1_params_t *params, uint16_t payload_length,
uint8_t *nb_hops_out )
{
// check length : payload + 16bit crc, encoded, padded to 48bits, adding 2 guard bit / 48bits
uint16_t length_bits = ( payload_length + 2 ) * 8 + 6;
switch( params->cr )
{
case LR_FHSS_V1_CR_5_6:
length_bits = ( ( length_bits * 6 ) + 4 ) / 5;
break;
case LR_FHSS_V1_CR_2_3:
length_bits = length_bits * 3 / 2;
break;
case LR_FHSS_V1_CR_1_2:
length_bits = length_bits * 2;
break;
case LR_FHSS_V1_CR_1_3:
length_bits = length_bits * 3;
break;
}
*nb_hops_out = ( length_bits + 47 ) / 48 + params->header_count;
// calculate total number of payload bits, after breaking into blocks
uint16_t payload_bits = length_bits / LR_FHSS_FRAG_BITS * LR_FHSS_BLOCK_BITS;
uint16_t last_block_bits = length_bits % LR_FHSS_FRAG_BITS;
if( last_block_bits > 0 )
{
// add the 2 guard bits for the last block + the actual remaining payload bits
payload_bits += last_block_bits + 2;
}
return ( LR_FHSS_HEADER_BITS * params->header_count ) + payload_bits;
}
/* --- EOF ------------------------------------------------------------------ */

View File

@@ -0,0 +1,198 @@
/*!
* @file lr_fhss_mac.h
*
* @brief Radio-independent LR-FHSS algorithms driver internal API
*
* The Clear BSD License
* Copyright Semtech Corporation 2021. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) 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 Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. 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 SEMTECH CORPORATION 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 LR_FHSS_MAC_H__
#define LR_FHSS_MAC_H__
/*
* -----------------------------------------------------------------------------
* --- DEPENDENCIES ------------------------------------------------------------
*/
#include <stdint.h>
#include <stdbool.h>
#include "radio_def.h"
#include "lr_fhss_v1_base_types.h"
/*
* -----------------------------------------------------------------------------
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC CONSTANTS --------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC TYPES ------------------------------------------------------------
*/
/*!
* Digest, holding physical payload length and hop information
*/
typedef struct lr_fhss_digest_s
{
uint16_t nb_bytes; /**< Length of LR-FHSS frame, in bytes */
uint16_t nb_bits; /**< Number of bits */
uint8_t nb_hops; /**< Number of hops */
} lr_fhss_digest_t;
/*!
* Hopping configuration, created by @ref lr_fhss_get_hop_params, and used to generate hop sequence
*/
typedef struct lr_fhss_hop_params_s
{
uint16_t n_grid; /**< Ngrid, as described in specification */
uint16_t polynomial; /**< polynomial, as described in specification, used for hop sequence generation */
uint16_t xoring_seed; /**< xoring seed, as described in specification, used for hop sequence generation */
uint16_t hop_sequence_id; /**< Hopping sequence seed, as described in specification, determines which hop sequence
will be used */
} lr_fhss_hop_params_t;
/*!
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @brief Return the number of hop sequences available using the given parameters
*
* @param [in] params LR-FHSS parameter structure
*
* @returns Number of valid hop sequences (512 or 384)
*/
unsigned int lr_fhss_get_hop_sequence_count( const lr_fhss_v1_params_t *params );
/*!
* @brief Fill the digest structure with various size-related data for a LR-FHSS frame
*
* @param [in] params LR-FHSS parameter structure
* @param [in] payload_length Length of payload, in bytes
* @param [out] digest Contains block count byte count, and number of hops
*/
void lr_fhss_process_parameters( const lr_fhss_v1_params_t *params, uint16_t payload_length, lr_fhss_digest_t *digest );
/*!
* @brief Fill the hop structure with various hop-related data for a LR-FHSS frame, and provide initial state
*
* @param [in] params LR-FHSS parameter structure
* @param [out] hop_params Hop parameter structure
* @param [out] initial_state Initial LFSR state
* @param [in] hop_sequence_id The hop sequence ID that will be used to obtain hop-related data
*
* @returns Operation status
*/
radio_status_t lr_fhss_get_hop_params( const lr_fhss_v1_params_t *params, lr_fhss_hop_params_t *hop_params,
uint16_t *initial_state, uint16_t hop_sequence_id );
/*!
* @brief Update the LFSR state by performing a hop, and return the hop grid position
*
* @param [in,out] lfsr_state LFSR state
* @param [in] hop_params Hop parameter structure
*
* @returns Hop position in the grid
*/
uint16_t lr_fhss_get_next_state( uint16_t *lfsr_state, const lr_fhss_hop_params_t *hop_params );
/*!
* @brief Return the frequency in grid units for given LR-FHSS parameters and hop index
*
* @param [in,out] lfsr_state LFSR state
* @param [in] hop_params Hop parameter structure
* @param [in] params LR-FHSS parameter structure
*
* @returns Frequency, in grid units
*/
int16_t lr_fhss_get_next_freq_in_grid( uint16_t *lfsr_state, const lr_fhss_hop_params_t *hop_params,
const lr_fhss_v1_params_t *params );
/*!
* @brief Construct the LR-FHSS frame
*
* @param [in] params LR-FHSS parameter structure
* @param [in] hop_sequence_id The hop sequence ID that will be used to obtain hop-related data
* @param [in] data_in Pointer to input buffer
* @param [in] data_in_bytecount Length of input buffer, in bytes
* @param [out] data_out Pointer to a buffer into which the final LR-FHSS frame is stored, large enough to hold
* 255 bytes
*
* @returns Length of frame, in bytes
*/
uint16_t lr_fhss_build_frame( const lr_fhss_v1_params_t *params, uint16_t hop_sequence_id, const uint8_t *data_in,
uint16_t data_in_bytecount, uint8_t *data_out );
/*!
* @brief Compute the numerator for LR-FHSS time-on-air computation.
*
* @remark To get the actual time-on-air in seconds, this value must be divided by the LR-FHSS bitrate in bits per
* second, 488.28125.
*
* @param [in] params LR-FHSS parameter structure
* @param [in] payload_length Length of application payload, in bytes
*
* @returns LR-FHSS time-on-air numerator
*/
static inline uint32_t lr_fhss_get_time_on_air_numerator( const lr_fhss_v1_params_t *params, uint16_t payload_length )
{
lr_fhss_digest_t digest;
lr_fhss_process_parameters( params, payload_length, &digest );
return digest.nb_bits;
}
/*!
* @brief Get the time on air in ms for LR-FHSS transmission
*
* @param [in] params LR-FHSS parameter structure
* @param [in] payload_length Length of application-layer payload
*
* @returns Time-on-air value in ms for LR-FHSS transmission
*/
uint32_t lr_fhss_get_time_on_air_in_ms( const lr_fhss_v1_params_t *params, uint16_t payload_length );
#ifdef __cplusplus
}
#endif
#endif // LR_FHSS_MAC_H__
/* --- EOF ------------------------------------------------------------------ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,154 @@
/**
******************************************************************************
* @file radio_fw.h
* @author MCD Application Team
* @brief Extends radio capabilities (whitening, long packet)
******************************************************************************
* @attention
*
* Copyright (c) 2020(-2021) 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.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __RADIO_FW_H__
#define __RADIO_FW_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "radio_def.h"
#include "radio_ex.h"
/* Exported types ------------------------------------------------------------*/
/*reserved for SubGHz_Phy internal MW communication*/
typedef enum
{
CONFIG_RX = 0,
CONFIG_TX,
} ConfigGenericRTx_t;
typedef struct
{
TxConfigGeneric_t *TxConfig;
RxConfigGeneric_t *RxConfig;
ConfigGenericRTx_t rtx;
} ConfigGeneric_t;
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
/*!
* @brief Initialise the RFW module and enables custom whitening, optionally long packet feature
*
* @param [in] config rx or tx config from the application
* @param [in] RadioEvents from the radio
* @param [in] TimeoutTimerEvent Timer for Rx or Tx timeout event
* @return 0 when no parameters error, -1 otherwise
*/
int32_t RFW_Init( ConfigGeneric_t *config, RadioEvents_t *RadioEvents, TimerEvent_t *TimeoutTimerEvent );
/*!
* @brief Return whether the RFW module is enabled
*
* @return 0 when not initialised, -1 otherwise
*/
uint8_t RFW_Is_Init( void );
/*!
* @brief Return whether the RFW module long packet is enabled
*
* @return 0 when not initialised, -1 otherwise
*/
uint8_t RFW_Is_LongPacketModeEnabled( void );
/*!
* @brief Return whether the RFW module long packet is enabled
*
* @param [in] Modem set in the radio
*/
void RFW_SetRadioModem( RadioModems_t Modem );
/*!
* @brief DeInitialise the RFW module and enable custom whitening and optionally long packet feature
*
*/
void RFW_DeInit( void );
/*!
* @brief DeInitialise the TxLongPacket
*
*/
void RFW_DeInit_TxLongPacket( void );
/*!
* @brief Set antenna switch output to be used in Tx
*
* @param [in] AntSwitch RFO_LP or FRO_HP
*
*/
void RFW_SetAntSwitch( uint8_t AntSwitch );
/*!
* @brief Initialise reception for IBM whitening case
*
* @return 0 when RFW_ENABLE exists, -1 otherwise
*/
int32_t RFW_ReceiveInit( void );
/*!
* @brief Initialise transmission for IBM whitening case
*
* @param [in,out] inOutBuffer pointer of exchange buffer to send or receive data
* @param [in] size input buffer size
* @param [out] outSize output buffer size
*
*/
int32_t RFW_TransmitInit( uint8_t *inOutBuffer, uint8_t size, uint8_t *outSize );
/*!
* @brief Starts receiving payload. Called at Rx Sync IRQ
*
*/
void RFW_ReceivePayload( void );
/*!
* @brief Starts transmitting long Packet, note packet length may be on 1 bytes depending on config
*
* @param [in] payload_size total payload size to be sent
* @param [in] timeout Reception timeout [ms]
* @param [in] TxLongPacketGetNextChunkCb callback to be implemented on user side to feed partial chunk
* buffer: source buffer allocated by the app
* size: size in bytes to feed. User to implement the offset based on previous chunk request
* @return 0 when no parameters error, -1 otherwise
*/
int32_t RFW_TransmitLongPacket( uint16_t payload_size, uint32_t timeout, void ( *TxLongPacketGetNextChunkCb )( uint8_t **buffer, uint8_t buffer_size ) );
/*!
* @brief Starts receiving long Packet, packet maybe short
*
* @param [in] boosted_mode boosted_mode: 0 normal Rx, 1:improved sensitivity
* @param [in] timeout Reception timeout [ms]
* @param [in] RxLongStorePacketChunkCb callback to be implemented on user side to record partial chunk in the application
* buffer: source buffer allocated in the radio driver
* size: size in bytes to record
* @return 0 when no parameters error, -1 otherwise
*/
int32_t RFW_ReceiveLongPacket( uint8_t boosted_mode, uint32_t timeout, void ( *RxLongStorePacketChunkCb )( uint8_t *buffer, uint8_t chunk_size ) );
#ifdef __cplusplus
}
#endif
#endif /*__RADIO_FW_H__*/

View File

@@ -0,0 +1,53 @@
/******************************************************************************
* @file subghz_phy_version.h
* @author MCD Application Team
* @brief defines the radio driver version
******************************************************************************
* @attention
*
* Copyright (c) 2020(-2021) 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.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SUBGHZ_PHY_VERSION_H__
#define __SUBGHZ_PHY_VERSION_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* __SUBGHZ_PHY_TYPE: 0x01 STM32WL
0x61 SX126X
0x72 SX1272
0x76 SX1276 */
#define SUBGHZ_PHY_VERSION_MAIN (0x01U) /*!< [31:24] main version */
#define SUBGHZ_PHY_VERSION_SUB1 (0x03U) /*!< [23:16] sub1 version */
#define SUBGHZ_PHY_VERSION_SUB2 (0x01U) /*!< [15:8] sub2 version */
#define SUBGHZ_PHY_TYPE (0x01U) /*!< [7:0] type version */
#define SUBGHZ_PHY_VERSION ((SUBGHZ_PHY_VERSION_MAIN << 24) \
|(SUBGHZ_PHY_VERSION_SUB1 << 16) \
|(SUBGHZ_PHY_VERSION_SUB2 << 8) \
|(SUBGHZ_PHY_TYPE))
/* Exported types ------------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
#ifdef __cplusplus
}
#endif
#endif /*__SUBGHZ_PHY_VERSION_H__*/

View File

@@ -0,0 +1,425 @@
/*!
* @file wl_lr_fhss.c
*
* @brief STM32WL LR-FHSS driver implementation
*
* The Clear BSD License
* Copyright Semtech Corporation 2021. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) 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 Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. 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 SEMTECH CORPORATION 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.
*/
/*
* -----------------------------------------------------------------------------
* --- DEPENDENCIES ------------------------------------------------------------
*/
#include "wl_lr_fhss.h"
#include "lr_fhss_mac.h"
/*
* -----------------------------------------------------------------------------
* --- PRIVATE MACROS-----------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PRIVATE CONSTANTS -------------------------------------------------------
*/
/* \cond */
#define WL_SET_MODULATION_PARAMS ( 0x8B )
#define WL_SET_PKT_PARAMS ( 0x8C )
#define WL_LR_FHSS_DISABLE_HOPPING ( 0 )
#define WL_LR_FHSS_ENABLE_HOPPING ( 1 )
#define WL_LR_FHSS_HOP_TABLE_SIZE ( 16 )
#define WL_LR_FHSS_HOP_ENTRY_SIZE ( 6 )
#define WL_LR_FHSS_GRID_3906_HZ_PLL_STEPS ( 4096 )
#define WL_LR_FHSS_GRID_25391_HZ_PLL_STEPS ( 26624 )
#define WL_LR_FHSS_GRID_INDEX_TO_PLL_STEPS ( 512 )
/* \endcond */
/*
* -----------------------------------------------------------------------------
* --- PRIVATE TYPES -----------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PRIVATE VARIABLES -------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PRIVATE FUNCTION DECLARATIONS -------------------------------------------
*/
/*!
* @brief Configure the radio to perform frequency hopping
*
* @param [in] context Chip implementation context
* @param [in] nb_bytes Total number of bytes
* @param [in] nb_hops Total number of hops
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_write_hop_config( const uint8_t nb_bytes, const uint8_t nb_hops );
/*!
* @brief Write a hop frequency/duration pair to the radio hop table
*
* @param [in] context Chip implementation context
* @param [in] index Index to chip hop table
* @param [in] nb_symbols Hop duration in symbols
* @param [in] freq_in_pll_steps Hop frequency, in PLL steps
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_write_hop( const uint8_t index, const uint16_t nb_symbols,
const uint32_t freq_in_pll_steps );
/*!
* @brief Get Frequency, in PLL steps, of the next hop
*
* @param [in] params stm32wl LR-FHSS parameter structure
* @param [out] state stm32wl LR-FHSS state structure that will be initialized by this function
*
* @returns Frequency, in PLL steps, of the next hop
*/
uint32_t wl_lr_fhss_get_next_freq_in_pll_steps( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state );
/*!
* @brief Get grid frequency, in PLL steps
*
* @param [in] params stm32wl LR-FHSS parameter structure
*
* @returns Grid frequency, in PLL steps
*/
static inline unsigned int wl_lr_fhss_get_grid_in_pll_steps( const wl_lr_fhss_params_t *params );
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS DEFINITION ---------------------------------------------
*/
radio_status_t wl_lr_fhss_init( const wl_lr_fhss_params_t *params )
{
radio_status_t status = RADIO_STATUS_OK;
SUBGRF_SetPacketType( PACKET_TYPE_LR_FHSS );
uint8_t pkt_params_buffer[8] = {0};
uint8_t mod_params_buffer[] = {32, 0, 0, MOD_SHAPING_G_BT_1, 0, 0, 0, 0};
SUBGRF_WriteCommand( RADIO_SET_PACKETPARAMS, pkt_params_buffer, sizeof( pkt_params_buffer ) );
SUBGRF_WriteCommand( RADIO_SET_MODULATIONPARAMS, mod_params_buffer, sizeof( mod_params_buffer ) );
SUBGRF_SetBufferBaseAddress( 0x00, 0x00 );
return status;
}
radio_status_t wl_lr_fhss_process_parameters( const wl_lr_fhss_params_t *params, uint16_t hop_sequence_id,
uint16_t payload_length, wl_lr_fhss_state_t *state )
{
lr_fhss_process_parameters( &params->lr_fhss_params, payload_length, &state->digest );
if( state->digest.nb_bytes > LR_FHSS_MAX_PHY_PAYLOAD_BYTES )
{
return RADIO_STATUS_UNKNOWN_VALUE;
}
if( params->lr_fhss_params.grid == LR_FHSS_V1_GRID_25391_HZ )
{
if( params->device_offset > 25 || params->device_offset < -26 )
{
return RADIO_STATUS_UNKNOWN_VALUE;
}
if( params->lr_fhss_params.bw < LR_FHSS_V1_BW_722656_HZ )
{
return RADIO_STATUS_UNKNOWN_VALUE;
}
}
if( params->lr_fhss_params.grid == LR_FHSS_V1_GRID_3906_HZ )
{
if( params->device_offset > 3 || params->device_offset < -4 )
{
return RADIO_STATUS_UNKNOWN_VALUE;
}
}
// Initialize hop index and params
state->current_hop = 0;
radio_status_t status =
lr_fhss_get_hop_params( &params->lr_fhss_params, &state->hop_params, &state->lfsr_state, hop_sequence_id );
if( status != RADIO_STATUS_OK )
{
return ( radio_status_t ) status;
}
// Skip the hop frequencies inside the set [0, 4 - header_count):
if( params->lr_fhss_params.enable_hopping != 0 )
{
for( int i = 0; i < 4 - params->lr_fhss_params.header_count; ++i )
{
lr_fhss_get_next_state( &state->lfsr_state, &state->hop_params );
}
}
state->next_freq_in_pll_steps = wl_lr_fhss_get_next_freq_in_pll_steps( params, state );
return RADIO_STATUS_OK;
}
radio_status_t wl_lr_fhss_write_hop_sequence_head( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state )
{
radio_status_t status = wl_lr_fhss_write_hop_config( state->digest.nb_bytes, state->digest.nb_hops );
if( status != RADIO_STATUS_OK )
{
return status;
}
const uint16_t pulse_shape_compensation = 1;
if( params->lr_fhss_params.enable_hopping == 0 )
{
// (LR_FHSS_HEADER_BITS + pulse_shape_compensation) symbols on first sync_word, LR_FHSS_HEADER_BITS on next
// sync_words, LR_FHSS_BLOCK_BITS on payload
const uint16_t nb_symbols = state->digest.nb_bits + pulse_shape_compensation;
status = wl_lr_fhss_write_hop( state->current_hop, nb_symbols, state->next_freq_in_pll_steps );
if( status != RADIO_STATUS_OK )
{
return status;
}
state->current_hop++;
state->digest.nb_bits = 0;
}
else
{
// fill at most WL_LR_FHSS_HOP_TABLE_SIZE hops of the hardware hop table
uint8_t truncated_hops = state->digest.nb_hops;
if( truncated_hops > WL_LR_FHSS_HOP_TABLE_SIZE )
{
truncated_hops = WL_LR_FHSS_HOP_TABLE_SIZE;
}
while( state->current_hop < truncated_hops )
{
uint16_t nb_symbols;
// (LR_FHSS_HEADER_BITS + pulse_shape_compensation) symbols on first sync_word, LR_FHSS_HEADER_BITS on
// next sync_words, LR_FHSS_BLOCK_BITS on payload
if( state->current_hop >= params->lr_fhss_params.header_count )
{
if( state->digest.nb_bits > LR_FHSS_BLOCK_BITS )
{
nb_symbols = LR_FHSS_BLOCK_BITS;
}
else
{
nb_symbols = state->digest.nb_bits;
}
}
else if( state->current_hop > 0 )
{
nb_symbols = LR_FHSS_HEADER_BITS;
}
else
{
nb_symbols = LR_FHSS_HEADER_BITS + pulse_shape_compensation;
}
status = wl_lr_fhss_write_hop( state->current_hop, nb_symbols, state->next_freq_in_pll_steps );
if( status != RADIO_STATUS_OK )
{
return status;
}
state->current_hop++;
state->digest.nb_bits -= nb_symbols;
state->next_freq_in_pll_steps = wl_lr_fhss_get_next_freq_in_pll_steps( params, state );
}
}
return status;
}
radio_status_t wl_lr_fhss_write_payload( const wl_lr_fhss_state_t *state,
const uint8_t *payload )
{
//return wl_write_buffer( context, 0x00, payload, state->digest.nb_bytes );
SUBGRF_WriteBuffer( 0x00, ( uint8_t * ) payload, state->digest.nb_bytes );
return RADIO_STATUS_OK;
}
radio_status_t wl_lr_fhss_build_frame( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state, uint16_t hop_sequence_id,
const uint8_t *payload, uint16_t payload_length,
uint32_t *first_frequency_in_pll_steps )
{
radio_status_t status = wl_lr_fhss_process_parameters( params, hop_sequence_id, payload_length, state );
if( status != RADIO_STATUS_OK )
{
return status;
}
if( first_frequency_in_pll_steps != NULL )
{
*first_frequency_in_pll_steps = state->next_freq_in_pll_steps;
}
uint8_t tx_buffer[LR_FHSS_MAX_PHY_PAYLOAD_BYTES];
lr_fhss_build_frame( &params->lr_fhss_params, state->hop_params.hop_sequence_id, payload, payload_length,
tx_buffer );
status = wl_lr_fhss_write_payload( state, tx_buffer );
if( status != RADIO_STATUS_OK )
{
return status;
}
status = wl_lr_fhss_write_hop_sequence_head( params, state );
return status;
}
radio_status_t wl_lr_fhss_handle_hop( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state )
{
if( state->current_hop < state->digest.nb_hops )
{
uint16_t nb_bits;
if( state->digest.nb_bits > LR_FHSS_BLOCK_BITS )
{
nb_bits = LR_FHSS_BLOCK_BITS;
}
else
{
nb_bits = state->digest.nb_bits;
}
radio_status_t status = wl_lr_fhss_write_hop( state->current_hop % WL_LR_FHSS_HOP_TABLE_SIZE,
LR_FHSS_BLOCK_BITS, state->next_freq_in_pll_steps );
if( status != RADIO_STATUS_OK )
{
return status;
}
state->current_hop++;
state->digest.nb_bits -= nb_bits;
state->next_freq_in_pll_steps = wl_lr_fhss_get_next_freq_in_pll_steps( params, state );
}
return RADIO_STATUS_OK;
}
radio_status_t wl_lr_fhss_handle_tx_done( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state )
{
//const uint8_t ctrl = WL_LR_FHSS_DISABLE_HOPPING;
//return wl_write_register( context, WL_LR_FHSS_REG_CTRL, &ctrl, 1 );
SUBGRF_WriteRegister( WL_LR_FHSS_REG_CTRL, WL_LR_FHSS_DISABLE_HOPPING );
return RADIO_STATUS_OK;
}
/*
* -----------------------------------------------------------------------------
* --- PRIVATE FUNCTIONS DEFINITION --------------------------------------------
*/
radio_status_t wl_lr_fhss_write_hop_config( const uint8_t nb_bytes, const uint8_t nb_hops )
{
uint8_t data[] = { WL_LR_FHSS_ENABLE_HOPPING, nb_bytes, nb_hops };
//return wl_write_register( context, WL_LR_FHSS_REG_CTRL, data, 3 );
SUBGRF_WriteRegisters( WL_LR_FHSS_REG_CTRL, data, 3 );
return RADIO_STATUS_OK;
}
radio_status_t wl_lr_fhss_write_hop( const uint8_t index, const uint16_t nb_symbols,
const uint32_t freq_in_pll_steps )
{
if( index >= WL_LR_FHSS_HOP_TABLE_SIZE )
{
return RADIO_STATUS_ERROR;
}
uint8_t data[WL_LR_FHSS_HOP_ENTRY_SIZE] =
{
( uint8_t )( nb_symbols >> 8 ), ( uint8_t ) nb_symbols,
( uint8_t )( freq_in_pll_steps >> 24 ), ( uint8_t )( freq_in_pll_steps >> 16 ),
( uint8_t )( freq_in_pll_steps >> 8 ), ( uint8_t ) freq_in_pll_steps,
};
//return wl_write_register( context, WL_LR_FHSS_REG_NUM_SYMBOLS_0 + ( WL_LR_FHSS_HOP_ENTRY_SIZE * index ),
// data, WL_LR_FHSS_HOP_ENTRY_SIZE );
SUBGRF_WriteRegisters( WL_LR_FHSS_REG_NUM_SYMBOLS_0 + ( WL_LR_FHSS_HOP_ENTRY_SIZE * index ),
data, WL_LR_FHSS_HOP_ENTRY_SIZE );
return RADIO_STATUS_OK;
}
uint32_t wl_lr_fhss_get_next_freq_in_pll_steps( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state )
{
#ifdef HOP_AT_CENTER_FREQ
const int16_t freq_table = 0;
uint32_t grid_offset = 0;
#else
const int16_t freq_table =
lr_fhss_get_next_freq_in_grid( &state->lfsr_state, &state->hop_params, &params->lr_fhss_params );
uint32_t nb_channel_in_grid = params->lr_fhss_params.grid ? 8 : 52;
uint32_t grid_offset = ( 1 + ( state->hop_params.n_grid % 2 ) ) * ( nb_channel_in_grid / 2 );
#endif
unsigned int grid_in_pll_steps = wl_lr_fhss_get_grid_in_pll_steps( params );
uint32_t freq = params->center_freq_in_pll_steps - freq_table * grid_in_pll_steps -
( params->device_offset + grid_offset ) * WL_LR_FHSS_GRID_INDEX_TO_PLL_STEPS;
#ifndef HOP_AT_CENTER_FREQ
// Perform frequency correction for every other sync header
if( params->lr_fhss_params.enable_hopping && ( state->current_hop < params->lr_fhss_params.header_count ) )
{
if( ( ( ( params->lr_fhss_params.header_count - state->current_hop ) % 2 ) == 0 ) )
{
// OFFSET_SYNCWORD = 488.28125 / 2, and FREQ_STEP = 0.95367431640625, so
// OFFSET_SYNCWORD / FREQ_STEP = 256
freq = freq + 256;
}
}
#endif
return freq;
}
static inline unsigned int wl_lr_fhss_get_grid_in_pll_steps( const wl_lr_fhss_params_t *params )
{
return ( params->lr_fhss_params.grid == LR_FHSS_V1_GRID_3906_HZ ) ? WL_LR_FHSS_GRID_3906_HZ_PLL_STEPS : WL_LR_FHSS_GRID_25391_HZ_PLL_STEPS;
}
/* --- EOF ------------------------------------------------------------------ */

View File

@@ -0,0 +1,238 @@
/*!
* @file wl_lr_fhss.h
*
* @brief STM32WL LR-FHSS driver module API (internal to SubGHz_Phy middleware)
*
* The Clear BSD License
* Copyright Semtech Corporation 2021. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) 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 Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. 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 SEMTECH CORPORATION 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 WL_LR_FHSS_H__
#define WL_LR_FHSS_H__
/*
* -----------------------------------------------------------------------------
* --- DEPENDENCIES ------------------------------------------------------------
*/
#include <stdint.h>
#include "radio_driver.h"
#include "lr_fhss_mac.h"
/*
* -----------------------------------------------------------------------------
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC CONSTANTS --------------------------------------------------------
*/
#define WL_LR_FHSS_REG_CTRL ( 0x0385 )
#define WL_LR_FHSS_REG_PACKET_LEN ( 0x0386 )
#define WL_LR_FHSS_REG_NUM_HOPS ( 0x0387 )
#define WL_LR_FHSS_REG_NUM_SYMBOLS_0 ( 0x0388 )
#define WL_LR_FHSS_REG_FREQ_0 ( 0x038A )
/*
* -----------------------------------------------------------------------------
* --- PUBLIC TYPES ------------------------------------------------------------
*/
/*!
* @brief STM32WL LR-FHSS LR-FHSS parameter definition
*/
typedef struct wl_lr_fhss_params_s
{
lr_fhss_v1_params_t lr_fhss_params;
uint32_t center_freq_in_pll_steps; /**< Center frequency in transceiver units */
int8_t device_offset; //<! Per device offset to avoid collisions over the air. Possible values:
//<! - if (lr_fhss_params.grid == LR_FHSS_V1_GRID_25391_HZ): [-26, 25]
//<! - if (lr_fhss_params.grid == LR_FHSS_V1_GRID_3906_HZ): [-4, 3]
} wl_lr_fhss_params_t;
/*!
* @brief STM32WL LR-FHSS LR-FHSS state definition
*/
typedef struct wl_lr_fhss_state_s
{
lr_fhss_hop_params_t hop_params;
lr_fhss_digest_t digest;
uint32_t next_freq_in_pll_steps; /**< Frequency that will be used on next hop */
uint16_t lfsr_state; /**< LFSR state for hop sequence generation */
uint8_t current_hop; /**< Index of the current hop */
} wl_lr_fhss_state_t;
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @brief Initialize LR-FHSS packet type and modulation parameters
*
* @param [in] params stm32wl LR-FHSS parameter structure
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_init( const wl_lr_fhss_params_t *params );
/*!
* @brief Check the parameters, and in case of success, generate the digest summary which contains important size info
*
* @param [in] params stm32wl LR-FHSS parameter structure
* @param [in] hop_sequence_id Specifies which hop sequence to use
* @param [in] payload_length Length of application-layer payload
* @param [out] state stm32wl LR-FHSS state structure that will be initialized by this function
*
* @remark It is not necessary to explicitly call this function if the helper function @ref wl_lr_fhss_build_frame
* is used. If the preprocessor symbol HOP_AT_CENTER_FREQ is defined, hopping will be performed with PA ramp
* up/down, but without actually changing frequencies.
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_process_parameters( const wl_lr_fhss_params_t *params, uint16_t hop_sequence_id,
uint16_t payload_length, wl_lr_fhss_state_t *state );
/*!
* @brief Sent the initial hopping confifguration to the radio
*
* @param [in] params stm32wl LR-FHSS parameter structure
* @param [in] state stm32wl LR-FHSS state structure
*
* @remark It is not necessary to explicitly call this function if the helper function @ref wl_lr_fhss_build_frame
* is used. If the preprocessor symbol HOP_AT_CENTER_FREQ is defined, hopping will be performed with PA ramp
* up/down, but without actually changing frequencies.
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_write_hop_sequence_head( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state );
/*!
* @brief Write physical LR-FHSS payload to radio
*
* @param [in] state stm32wl LR-FHSS state structure
* @param [in] payload Array containing application-layer payload
*
* @remark It is not necessary to explicitly call this function if the helper function @ref wl_lr_fhss_build_frame
* is used.
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_write_payload( const wl_lr_fhss_state_t *state,
const uint8_t *payload );
/*!
* @brief Check parameter validity, build a frame, then send it
*
* @param [in] params stm32wl LR-FHSS parameter structure
* @param [in] state stm32wl LR-FHSS state structure
* @param [in] hop_sequence_id Specifies which hop sequence to use
* @param [in] payload Array containing application-layer payload
* @param [in] payload_length Length of application-layer payload
* @param [out] first_frequency_in_pll_steps If non-NULL, provides the frequency that will be used on the first hop
*
* @remark This helper function calls the @ref wl_lr_fhss_process_parameters,
* lr_fhss_build_frame, @ref wl_lr_fhss_write_hop_sequence_head, and @ref wl_lr_fhss_write_payload
* functions. If the preprocessor symbol HOP_AT_CENTER_FREQ is defined, hopping will be performed with PA ramp
* up/down, but without actually changing frequencies.
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_build_frame( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state, uint16_t hop_sequence_id,
const uint8_t *payload, uint16_t payload_length,
uint32_t *first_frequency_in_pll_steps );
/*!
* @brief Perform an actual frequency hop
*
* @param [in] params stm32wl LR-FHSS parameter structure
* @param [in] state stm32wl LR-FHSS state structure
*
* @remark This should be called to respond to the WL_IRQ_LR_FHSS_HOP interrupt. If the preprocessor symbol
* HOP_AT_CENTER_FREQ is defined, hopping will be performed with PA ramp up/down, but without actually
* changing frequencies.
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_handle_hop( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state );
/*!
* @brief Indicate to the radio that frequency hopping is no longer needed
*
* @param [in] params stm32wl LR-FHSS parameter structure
* @param [in] state stm32wl LR-FHSS state structure
*
* @remark The should be called to respond to the WL_IRQ_TX_DONE interrupt following LR-FHSS transmission.
*
* @returns Operation status
*/
radio_status_t wl_lr_fhss_handle_tx_done( const wl_lr_fhss_params_t *params,
wl_lr_fhss_state_t *state );
/*!
* @brief Get the time on air in ms for LR-FHSS transmission
*
* @param [in] params stm32wl LR-FHSS parameter structure
* @param [in] payload_length Length of application-layer payload
*
* @returns Time-on-air value in ms for LR-FHSS transmission
*/
static inline uint32_t wl_lr_fhss_get_time_on_air_in_ms( const wl_lr_fhss_params_t *params,
uint16_t payload_length )
{
return lr_fhss_get_time_on_air_in_ms( &params->lr_fhss_params, payload_length );
}
/*!
* @brief Return the number of hop sequences available using the given parameters
*
* @param [in] params stm32wl LR-FHSS parameter structure
*
* @return Returns the number of valid hop sequences (512 or 384)
*/
static inline unsigned int wl_lr_fhss_get_hop_sequence_count( const wl_lr_fhss_params_t *params )
{
return lr_fhss_get_hop_sequence_count( &params->lr_fhss_params );
}
#ifdef __cplusplus
}
#endif
#endif // WL_LR_FHSS_H__
/* --- EOF ------------------------------------------------------------------ */