1 /*!
2  * \file      RegionBaseUS.c
3  *
4  * \brief     Implementations common with US region.
5  *
6  * \copyright Revised BSD License, see section \ref LICENSE.
7  *
8  * \code
9  *                ______                              _
10  *               / _____)             _              | |
11  *              ( (____  _____ ____ _| |_ _____  ____| |__
12  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
13  *               _____) ) ____| | | || |_| ____( (___| | | |
14  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
15  *              (C)2013-2017 Semtech
16  *
17  *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
18  *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
19  *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
20  *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
21  *              embedded.connectivity.solutions===============
22  *
23  * \endcode
24  *
25  * \author    Miguel Luis ( Semtech )
26  *
27  * \author    Gregory Cristian ( Semtech )
28  *
29  * \author    Daniel Jaeckle ( STACKFORCE )
30  *
31  * \author    Phanindra Kumar Yellapu ( STACKFORCE )
32  */
33 #include "LoRaMacTypes.h"
34 #include "region/Region.h"
35 #include "RegionBaseUS.h"
36 
37 
38 /*!
39  * \brief Searches for available 125 kHz channels in the given channel mask.
40  *
41  * \param [IN] currentChannelMaskLeft The remaining channel mask.
42  *
43  * \param [OUT] findAvailableChannelsIndex List containing the indexes of all available 125 kHz channels.
44  *
45  * \param [OUT] availableChannels Number of available 125 kHz channels.
46  *
47  * \retval Status
48  */
FindAvailable125kHzChannels(uint16_t currentChannelMaskLeft,uint8_t * findAvailableChannelsIndex,uint8_t * availableChannels)49 static LoRaMacStatus_t FindAvailable125kHzChannels( uint16_t currentChannelMaskLeft,
50                                                     uint8_t* findAvailableChannelsIndex, uint8_t* availableChannels )
51 {
52     // Nullpointer check
53     if( findAvailableChannelsIndex == NULL || availableChannels == NULL )
54     {
55         return LORAMAC_STATUS_PARAMETER_INVALID;
56     }
57 
58     // Initialize counter
59     *availableChannels = 0;
60     for( uint8_t i = 0; i < 8; i++ )
61     {
62         // Find available channels
63         if( ( currentChannelMaskLeft & ( 1 << i ) ) != 0 )
64         {
65             // Save available channel index
66             findAvailableChannelsIndex[*availableChannels] = i;
67             // Increment counter of available channels if the current channel is available
68             ( *availableChannels )++;
69         }
70     }
71 
72     return LORAMAC_STATUS_OK;
73 }
74 
RegionBaseUSComputeNext125kHzJoinChannel(uint16_t * channelsMaskRemaining,uint8_t * groupsCurrentIndex,uint8_t * newChannelIndex)75 LoRaMacStatus_t RegionBaseUSComputeNext125kHzJoinChannel( uint16_t* channelsMaskRemaining,
76                                                           uint8_t* groupsCurrentIndex, uint8_t* newChannelIndex )
77 {
78     uint8_t currentChannelMaskLeftIndex;
79     uint16_t currentChannelMaskLeft;
80     uint8_t findAvailableChannelsIndex[8] = { 0 };
81     uint8_t availableChannels = 0;
82     uint8_t startIndex;
83 
84     // Null pointer check
85     if( channelsMaskRemaining == NULL || groupsCurrentIndex == NULL || newChannelIndex == NULL )
86     {
87         return LORAMAC_STATUS_PARAMETER_INVALID;
88     }
89 
90     // copy the current index.
91     startIndex = *groupsCurrentIndex;
92 
93     do
94     {
95         // Current ChannelMaskRemaining, two groups per channel mask. For example Group 0 and 1 (8 bit) are ChannelMaskRemaining 0 (16 bit), etc.
96         currentChannelMaskLeftIndex = (uint8_t) startIndex / 2;
97 
98         // For even numbers we need the 8 LSBs and for uneven the 8 MSBs
99         if( ( startIndex % 2 ) == 0 )
100         {
101             currentChannelMaskLeft = ( channelsMaskRemaining[currentChannelMaskLeftIndex] & 0x00FF );
102         }
103         else
104         {
105             currentChannelMaskLeft = ( ( channelsMaskRemaining[currentChannelMaskLeftIndex] >> 8 ) & 0x00FF );
106         }
107 
108 
109         if( FindAvailable125kHzChannels( currentChannelMaskLeft, findAvailableChannelsIndex, &availableChannels ) == LORAMAC_STATUS_PARAMETER_INVALID )
110         {
111             return LORAMAC_STATUS_PARAMETER_INVALID;
112         }
113 
114         if ( availableChannels > 0 )
115         {
116             // Choose randomly a free channel 125kHz
117             *newChannelIndex = ( startIndex * 8 ) + findAvailableChannelsIndex[randr( 0, ( availableChannels - 1 ) )];
118         }
119 
120         // Increment start index
121         startIndex++;
122         if ( startIndex > 7 )
123         {
124             startIndex = 0;
125         }
126     } while( ( availableChannels == 0 ) && ( startIndex != *groupsCurrentIndex ) );
127 
128     if ( availableChannels > 0 )
129     {
130         *groupsCurrentIndex = startIndex;
131         return LORAMAC_STATUS_OK;
132     }
133 
134     return LORAMAC_STATUS_PARAMETER_INVALID;
135 }
136 
RegionBaseUSVerifyFrequencyGroup(uint32_t freq,uint32_t minFreq,uint32_t maxFreq,uint32_t stepwidth)137 bool RegionBaseUSVerifyFrequencyGroup( uint32_t freq, uint32_t minFreq, uint32_t maxFreq, uint32_t stepwidth )
138 {
139     if( ( freq < minFreq ) ||
140         ( freq > maxFreq ) ||
141         ( ( ( freq - ( uint32_t ) minFreq ) % ( uint32_t ) stepwidth ) != 0 ) )
142     {
143         return false;
144     }
145     return true;
146 }
147 
RegionBaseUSCalcDownlinkFrequency(uint8_t channel,uint32_t frequency,uint32_t stepwidth)148 uint32_t RegionBaseUSCalcDownlinkFrequency( uint8_t channel, uint32_t frequency,
149                                             uint32_t stepwidth )
150 {
151     // Calculate the frequency
152     return frequency + ( channel * stepwidth );
153 }
154