• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2022, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "power_calibration.hpp"
30 
31 #if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
32 #include <openthread/platform/diag.h>
33 
34 #include "common/as_core_type.hpp"
35 #include "common/code_utils.hpp"
36 #include "common/locator_getters.hpp"
37 
38 namespace ot {
39 namespace Utils {
40 
PowerCalibration(Instance & aInstance)41 PowerCalibration::PowerCalibration(Instance &aInstance)
42     : InstanceLocator(aInstance)
43     , mLastChannel(0)
44     , mCalibratedPowerIndex(kInvalidIndex)
45 {
46     for (int16_t &targetPower : mTargetPowerTable)
47     {
48         targetPower = kInvalidPower;
49     }
50 }
51 
Init(int16_t aActualPower,const uint8_t * aRawPowerSetting,uint16_t aRawPowerSettingLength)52 void PowerCalibration::CalibratedPowerEntry::Init(int16_t        aActualPower,
53                                                   const uint8_t *aRawPowerSetting,
54                                                   uint16_t       aRawPowerSettingLength)
55 {
56     AssertPointerIsNotNull(aRawPowerSetting);
57     OT_ASSERT(aRawPowerSettingLength <= kMaxRawPowerSettingSize);
58 
59     mActualPower = aActualPower;
60     mLength      = aRawPowerSettingLength;
61     memcpy(mSettings, aRawPowerSetting, aRawPowerSettingLength);
62 }
63 
GetRawPowerSetting(uint8_t * aRawPowerSetting,uint16_t * aRawPowerSettingLength)64 Error PowerCalibration::CalibratedPowerEntry::GetRawPowerSetting(uint8_t  *aRawPowerSetting,
65                                                                  uint16_t *aRawPowerSettingLength)
66 {
67     Error error = kErrorNone;
68 
69     AssertPointerIsNotNull(aRawPowerSetting);
70     AssertPointerIsNotNull(aRawPowerSettingLength);
71     VerifyOrExit(*aRawPowerSettingLength >= mLength, error = kErrorInvalidArgs);
72 
73     memcpy(aRawPowerSetting, mSettings, mLength);
74     *aRawPowerSettingLength = mLength;
75 
76 exit:
77     return error;
78 }
79 
AddCalibratedPower(uint8_t aChannel,int16_t aActualPower,const uint8_t * aRawPowerSetting,uint16_t aRawPowerSettingLength)80 Error PowerCalibration::AddCalibratedPower(uint8_t        aChannel,
81                                            int16_t        aActualPower,
82                                            const uint8_t *aRawPowerSetting,
83                                            uint16_t       aRawPowerSettingLength)
84 {
85     Error                error = kErrorNone;
86     CalibratedPowerEntry entry;
87     uint8_t              chIndex;
88 
89     AssertPointerIsNotNull(aRawPowerSetting);
90     VerifyOrExit(IsChannelValid(aChannel) && aRawPowerSettingLength <= CalibratedPowerEntry::kMaxRawPowerSettingSize,
91                  error = kErrorInvalidArgs);
92 
93     chIndex = aChannel - Radio::kChannelMin;
94     VerifyOrExit(!mCalibratedPowerTables[chIndex].ContainsMatching(aActualPower), error = kErrorInvalidArgs);
95     VerifyOrExit(!mCalibratedPowerTables[chIndex].IsFull(), error = kErrorNoBufs);
96 
97     entry.Init(aActualPower, aRawPowerSetting, aRawPowerSettingLength);
98     SuccessOrExit(error = mCalibratedPowerTables[chIndex].PushBack(entry));
99 
100     if (aChannel == mLastChannel)
101     {
102         mCalibratedPowerIndex = kInvalidIndex;
103     }
104 
105 exit:
106     return error;
107 }
108 
ClearCalibratedPowers(void)109 void PowerCalibration::ClearCalibratedPowers(void)
110 {
111     for (CalibratedPowerTable &table : mCalibratedPowerTables)
112     {
113         table.Clear();
114     }
115 
116     mCalibratedPowerIndex = kInvalidIndex;
117 }
118 
SetChannelTargetPower(uint8_t aChannel,int16_t aTargetPower)119 Error PowerCalibration::SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower)
120 {
121     Error error = kErrorNone;
122 
123     VerifyOrExit(IsChannelValid(aChannel), error = kErrorInvalidArgs);
124     mTargetPowerTable[aChannel - Radio::kChannelMin] = aTargetPower;
125 
126     if (aChannel == mLastChannel)
127     {
128         mCalibratedPowerIndex = kInvalidIndex;
129     }
130 
131 exit:
132     return error;
133 }
134 
GetPowerSettings(uint8_t aChannel,int16_t * aTargetPower,int16_t * aActualPower,uint8_t * aRawPowerSetting,uint16_t * aRawPowerSettingLength)135 Error PowerCalibration::GetPowerSettings(uint8_t   aChannel,
136                                          int16_t  *aTargetPower,
137                                          int16_t  *aActualPower,
138                                          uint8_t  *aRawPowerSetting,
139                                          uint16_t *aRawPowerSettingLength)
140 {
141     Error   error = kErrorNone;
142     uint8_t chIndex;
143     uint8_t powerIndex = kInvalidIndex;
144     int16_t foundPower = kInvalidPower;
145     int16_t targetPower;
146     int16_t actualPower;
147 
148     VerifyOrExit(IsChannelValid(aChannel), error = kErrorInvalidArgs);
149     VerifyOrExit((mLastChannel != aChannel) || IsPowerUpdated());
150 
151     chIndex     = aChannel - Radio::kChannelMin;
152     targetPower = mTargetPowerTable[chIndex];
153     VerifyOrExit(targetPower != kInvalidPower, error = kErrorNotFound);
154 
155     for (uint8_t i = 0; i < mCalibratedPowerTables[chIndex].GetLength(); i++)
156     {
157         actualPower = mCalibratedPowerTables[chIndex][i].GetActualPower();
158 
159         if ((actualPower <= targetPower) && ((foundPower == kInvalidPower) || (foundPower <= actualPower)))
160         {
161             foundPower = actualPower;
162             powerIndex = i;
163         }
164     }
165 
166     VerifyOrExit(powerIndex != kInvalidIndex, error = kErrorNotFound);
167 
168     mCalibratedPowerIndex = powerIndex;
169     mLastChannel          = aChannel;
170 
171 exit:
172     if (error == kErrorNone)
173     {
174         chIndex = mLastChannel - Radio::kChannelMin;
175 
176         if (aTargetPower != nullptr)
177         {
178             *aTargetPower = mTargetPowerTable[chIndex];
179         }
180 
181         if (aActualPower != nullptr)
182         {
183             *aActualPower = mCalibratedPowerTables[chIndex][mCalibratedPowerIndex].GetActualPower();
184         }
185 
186         error = mCalibratedPowerTables[chIndex][mCalibratedPowerIndex].GetRawPowerSetting(aRawPowerSetting,
187                                                                                           aRawPowerSettingLength);
188     }
189 
190     return error;
191 }
192 } // namespace Utils
193 } // namespace ot
194 
195 using namespace ot;
196 
otPlatRadioAddCalibratedPower(otInstance * aInstance,uint8_t aChannel,int16_t aActualPower,const uint8_t * aRawPowerSetting,uint16_t aRawPowerSettingLength)197 otError otPlatRadioAddCalibratedPower(otInstance    *aInstance,
198                                       uint8_t        aChannel,
199                                       int16_t        aActualPower,
200                                       const uint8_t *aRawPowerSetting,
201                                       uint16_t       aRawPowerSettingLength)
202 {
203     return AsCoreType(aInstance).Get<Utils::PowerCalibration>().AddCalibratedPower(
204         aChannel, aActualPower, aRawPowerSetting, aRawPowerSettingLength);
205 }
206 
otPlatRadioClearCalibratedPowers(otInstance * aInstance)207 otError otPlatRadioClearCalibratedPowers(otInstance *aInstance)
208 {
209     AsCoreType(aInstance).Get<Utils::PowerCalibration>().ClearCalibratedPowers();
210     return OT_ERROR_NONE;
211 }
212 
otPlatRadioSetChannelTargetPower(otInstance * aInstance,uint8_t aChannel,int16_t aTargetPower)213 otError otPlatRadioSetChannelTargetPower(otInstance *aInstance, uint8_t aChannel, int16_t aTargetPower)
214 {
215     return AsCoreType(aInstance).Get<Utils::PowerCalibration>().SetChannelTargetPower(aChannel, aTargetPower);
216 }
217 
otPlatRadioGetRawPowerSetting(otInstance * aInstance,uint8_t aChannel,uint8_t * aRawPowerSetting,uint16_t * aRawPowerSettingLength)218 otError otPlatRadioGetRawPowerSetting(otInstance *aInstance,
219                                       uint8_t     aChannel,
220                                       uint8_t    *aRawPowerSetting,
221                                       uint16_t   *aRawPowerSettingLength)
222 {
223     AssertPointerIsNotNull(aRawPowerSetting);
224     AssertPointerIsNotNull(aRawPowerSettingLength);
225 
226     return AsCoreType(aInstance).Get<Utils::PowerCalibration>().GetPowerSettings(
227         aChannel, nullptr, nullptr, aRawPowerSetting, aRawPowerSettingLength);
228 }
229 
otPlatDiagRadioGetPowerSettings(otInstance * aInstance,uint8_t aChannel,int16_t * aTargetPower,int16_t * aActualPower,uint8_t * aRawPowerSetting,uint16_t * aRawPowerSettingLength)230 otError otPlatDiagRadioGetPowerSettings(otInstance *aInstance,
231                                         uint8_t     aChannel,
232                                         int16_t    *aTargetPower,
233                                         int16_t    *aActualPower,
234                                         uint8_t    *aRawPowerSetting,
235                                         uint16_t   *aRawPowerSettingLength)
236 {
237     OT_UNUSED_VARIABLE(aInstance);
238 
239     AssertPointerIsNotNull(aRawPowerSetting);
240     AssertPointerIsNotNull(aRawPowerSettingLength);
241 
242     return AsCoreType(aInstance).Get<Utils::PowerCalibration>().GetPowerSettings(
243         aChannel, aTargetPower, aActualPower, aRawPowerSetting, aRawPowerSettingLength);
244 }
245 #endif // OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
246