1 /*!
2  * \file      RegionCN470A20.c
3  *
4  * \brief
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    Daniel Jaeckle ( STACKFORCE )
28  *
29  * \defgroup  REGIONCN470
30  */
31 #include "RegionCN470.h"
32 #include "RegionBaseUS.h"
33 #include "RegionCN470A20.h"
34 
RegionCN470A20GetDownlinkFrequency(uint8_t channel,uint8_t joinChannelIndex,bool isPingSlot)35 uint32_t RegionCN470A20GetDownlinkFrequency( uint8_t channel, uint8_t joinChannelIndex, bool isPingSlot )
36 {
37     return RegionCN470A20GetRx1Frequency( channel );
38 }
39 
RegionCN470A20GetBeaconChannelOffset(uint8_t joinChannelIndex)40 uint8_t RegionCN470A20GetBeaconChannelOffset( uint8_t joinChannelIndex )
41 {
42     return ( joinChannelIndex * 8 );
43 }
44 
RegionCN470A20LinkAdrChMaskUpdate(uint16_t * channelsMask,uint8_t chMaskCntl,uint16_t chanMask,ChannelParams_t * channels)45 uint8_t RegionCN470A20LinkAdrChMaskUpdate( uint16_t* channelsMask, uint8_t chMaskCntl,
46                                            uint16_t chanMask, ChannelParams_t* channels )
47 {
48     uint8_t status = 0x07;
49 
50     if( ( chMaskCntl == 4 ) || ( chMaskCntl == 5 ) )
51     {
52         // RFU
53         status &= 0xFE; // Channel mask KO
54     }
55     else if( chMaskCntl == 6 )
56     {
57         // Enable all channels
58         channelsMask[0] = 0xFFFF;
59         channelsMask[1] = 0xFFFF;
60         channelsMask[2] = 0xFFFF;
61         channelsMask[3] = 0xFFFF;
62         channelsMask[4] = 0x0000;
63         channelsMask[5] = 0x0000;
64     }
65     else if( chMaskCntl == 7 )
66     {
67         // Disable all channels
68         channelsMask[0] = 0x0000;
69         channelsMask[1] = 0x0000;
70         channelsMask[2] = 0x0000;
71         channelsMask[3] = 0x0000;
72         channelsMask[4] = 0x0000;
73         channelsMask[5] = 0x0000;
74     }
75     else
76     {
77         // chMaskCntl 0 to 3
78         for( uint8_t i = 0; i < 16; i++ )
79         {
80             if( ( ( chanMask & ( 1 << i ) ) != 0 ) &&
81                 ( channels[chMaskCntl * 16 + i].Frequency == 0 ) )
82             {// Trying to enable an undefined channel
83                 status &= 0xFE; // Channel mask KO
84             }
85         }
86             channelsMask[chMaskCntl] = chanMask;
87     }
88     return status;
89 }
90 
RegionCN470A20VerifyRfFreq(uint32_t freq)91 bool RegionCN470A20VerifyRfFreq( uint32_t freq )
92 {
93     // Downstream group 1 and 2
94     if( RegionBaseUSVerifyFrequencyGroup( freq, CN470_A20_FIRST_RX_CHANNEL,
95                                           CN470_A20_LAST_RX_CHANNEL,
96                                           CN470_A20_STEPWIDTH_RX_CHANNEL ) == false )
97     {
98         return false;
99     }
100     return true;
101 }
102 
RegionCN470A20InitializeChannels(ChannelParams_t * channels)103 void RegionCN470A20InitializeChannels( ChannelParams_t* channels )
104 {
105     // Upstream group 1
106     for( uint8_t i = 0; i < 32; i++ )
107     {
108         channels[i].Frequency = CN470_A20_FIRST_TX1_CHANNEL + i * CN470_A20_STEPWIDTH_RX_CHANNEL;
109         channels[i].DrRange.Value = ( CN470_TX_MAX_DATARATE << 4 ) | CN470_TX_MIN_DATARATE;
110         channels[i].Band = 0;
111     }
112     // Upstream group 2
113     for( uint8_t i = 32; i < 64; i++ )
114     {
115         channels[i].Frequency = CN470_A20_FIRST_TX2_CHANNEL + ( i - 32 ) * CN470_A20_STEPWIDTH_RX_CHANNEL;
116         channels[i].DrRange.Value = ( CN470_TX_MAX_DATARATE << 4 ) | CN470_TX_MIN_DATARATE;
117         channels[i].Band = 0;
118     }
119 }
120 
RegionCN470A20InitializeChannelsMask(uint16_t * channelsDefaultMask)121 void RegionCN470A20InitializeChannelsMask(  uint16_t* channelsDefaultMask )
122 {
123     // Enable all possible channels
124     channelsDefaultMask[0] = 0xFFFF;
125     channelsDefaultMask[1] = 0xFFFF;
126     channelsDefaultMask[2] = 0xFFFF;
127     channelsDefaultMask[3] = 0xFFFF;
128     channelsDefaultMask[4] = 0x0000;
129     channelsDefaultMask[5] = 0x0000;
130 }
131 
RegionCN470A20GetRx1Frequency(uint8_t channel)132 uint32_t RegionCN470A20GetRx1Frequency( uint8_t channel )
133 {
134     // Base frequency for downstream group 1
135     uint32_t baseFrequency = CN470_A20_FIRST_RX_CHANNEL;
136     uint8_t offset = 0;
137 
138     if( channel >= 32 )
139     {
140         // Base frequency for downstream group 2
141         baseFrequency = 490300000;
142         offset = 32;
143     }
144     return ( baseFrequency + ( ( channel - offset ) * CN470_A20_STEPWIDTH_RX_CHANNEL ) );
145 }
146 
RegionCN470A20GetRx2Frequency(uint8_t joinChannelIndex,bool isOtaaDevice)147 uint32_t RegionCN470A20GetRx2Frequency( uint8_t joinChannelIndex, bool isOtaaDevice )
148 {
149     uint32_t otaaFrequencies[] = CN470_A20_RX_WND_2_FREQ_OTAA;
150 
151     if( isOtaaDevice == true )
152     {
153         return otaaFrequencies[joinChannelIndex];
154     }
155     // ABP device
156     return CN470_A20_RX_WND_2_FREQ_ABP;
157 }
158 
159