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