1 /* 2 * Copyright (c) 2016, 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 /** 30 * @file 31 * This file contains definitions for the diagnostics module. 32 */ 33 34 #ifndef FACTORY_DIAGS_HPP_ 35 #define FACTORY_DIAGS_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_CONFIG_DIAG_ENABLE 40 41 #include <string.h> 42 43 #include <openthread/diag.h> 44 #include <openthread/platform/radio.h> 45 46 #include "common/clearable.hpp" 47 #include "common/error.hpp" 48 #include "common/locator.hpp" 49 #include "common/non_copyable.hpp" 50 #include "common/string.hpp" 51 #include "mac/mac_types.hpp" 52 53 namespace ot { 54 namespace FactoryDiags { 55 56 class Diags : public InstanceLocator, private NonCopyable 57 { 58 public: 59 /** 60 * Constructor. 61 * 62 * @param[in] aInstance The OpenThread instance. 63 */ 64 explicit Diags(Instance &aInstance); 65 66 /** 67 * Processes a factory diagnostics command line. 68 * 69 * @param[in] aString A null-terminated input string. 70 */ 71 Error ProcessLine(const char *aString); 72 73 /** 74 * Processes a factory diagnostics command line. 75 * 76 * @param[in] aArgsLength The number of args in @p aArgs. 77 * @param[in] aArgs The arguments of diagnostics command line. 78 * 79 * @retval kErrorInvalidArgs The command is supported but invalid arguments provided. 80 * @retval kErrorNone The command is successfully process. 81 * @retval kErrorNotImplemented The command is not supported. 82 */ 83 Error ProcessCmd(uint8_t aArgsLength, char *aArgs[]); 84 85 /** 86 * Indicates whether or not the factory diagnostics mode is enabled. 87 * 88 * @retval TRUE if factory diagnostics mode is enabled 89 * @retval FALSE if factory diagnostics mode is disabled. 90 */ 91 bool IsEnabled(void); 92 93 /** 94 * The platform driver calls this method to notify OpenThread diagnostics module that the alarm has fired. 95 */ 96 void AlarmFired(void); 97 98 /** 99 * The radio driver calls this method to notify OpenThread diagnostics module of a received frame. 100 * 101 * @param[in] aFrame A pointer to the received frame or `nullptr` if the receive operation failed. 102 * @param[in] aError kErrorNone when successfully received a frame, 103 * kErrorAbort when reception was aborted and a frame was not received, 104 * kErrorNoBufs when a frame could not be received due to lack of rx buffer space. 105 */ 106 void ReceiveDone(otRadioFrame *aFrame, Error aError); 107 108 /** 109 * The radio driver calls this method to notify OpenThread diagnostics module that the transmission has completed. 110 * 111 * @param[in] aError kErrorNone when the frame was transmitted, 112 * kErrorChannelAccessFailure tx could not take place due to activity on channel, 113 * kErrorAbort when transmission was aborted for other reasons. 114 */ 115 void TransmitDone(Error aError); 116 117 /** 118 * Sets the diag output callback. 119 * 120 * @param[in] aCallback A callback method called to output diag messages. 121 * @param[in] aContext A user context pointer. 122 */ 123 void SetOutputCallback(otDiagOutputCallback aCallback, void *aContext); 124 125 private: 126 static constexpr uint8_t kMaxArgs = OPENTHREAD_CONFIG_DIAG_CMD_LINE_ARGS_MAX; 127 128 struct Command 129 { 130 const char *mName; 131 Error (Diags::*mCommand)(uint8_t aArgsLength, char *aArgs[]); 132 }; 133 134 struct Stats : public Clearable<Stats> 135 { 136 uint32_t mReceivedPackets; 137 uint32_t mSentSuccessPackets; 138 uint32_t mSentFailedPackets; 139 uint32_t mSentErrorCcaPackets; 140 uint32_t mSentErrorAbortPackets; 141 uint32_t mSentErrorInvalidStatePackets; 142 uint32_t mSentErrorOthersPackets; 143 int8_t mFirstRssi; 144 uint8_t mFirstLqi; 145 int8_t mLastRssi; 146 uint8_t mLastLqi; 147 }; 148 149 struct RawPowerSetting 150 { 151 static constexpr uint16_t kMaxDataSize = OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE; 152 static constexpr uint16_t kInfoStringSize = kMaxDataSize * 2 + 1; 153 typedef String<kInfoStringSize> InfoString; 154 ToStringot::FactoryDiags::Diags::RawPowerSetting155 InfoString ToString(void) const 156 { 157 InfoString string; 158 159 string.AppendHexBytes(mData, mLength); 160 161 return string; 162 } 163 operator !=ot::FactoryDiags::Diags::RawPowerSetting164 bool operator!=(const RawPowerSetting &aOther) const 165 { 166 return (mLength != aOther.mLength) || (memcmp(mData, aOther.mData, mLength) != 0); 167 } 168 169 uint8_t mData[kMaxDataSize]; 170 uint16_t mLength; 171 }; 172 173 struct PowerSettings 174 { operator !=ot::FactoryDiags::Diags::PowerSettings175 bool operator!=(const PowerSettings &aOther) const 176 { 177 return (mTargetPower != aOther.mTargetPower) || (mActualPower != aOther.mActualPower) || 178 (mRawPowerSetting != aOther.mRawPowerSetting); 179 } 180 181 int16_t mTargetPower; 182 int16_t mActualPower; 183 RawPowerSetting mRawPowerSetting; 184 }; 185 186 struct ReceiveConfig 187 { ReceiveConfigot::FactoryDiags::Diags::ReceiveConfig188 ReceiveConfig(void) 189 : mIsEnabled(false) 190 , mIsAsyncCommand(false) 191 , mShowRssi(true) 192 , mShowLqi(true) 193 , mShowPsdu(false) 194 , mIsFilterEnabled(false) 195 , mReceiveCount(0) 196 , mNumFrames(0) 197 , mFilterAddress() 198 { 199 } 200 201 bool mIsEnabled : 1; 202 bool mIsAsyncCommand : 1; 203 bool mShowRssi : 1; 204 bool mShowLqi : 1; 205 bool mShowPsdu : 1; 206 bool mIsFilterEnabled : 1; 207 208 uint16_t mReceiveCount; 209 uint16_t mNumFrames; 210 Mac::Address mFilterAddress; 211 }; 212 213 Error ParseCmd(char *aString, uint8_t &aArgsLength, char *aArgs[]); 214 Error ProcessChannel(uint8_t aArgsLength, char *aArgs[]); 215 Error ProcessFrame(uint8_t aArgsLength, char *aArgs[]); 216 Error ProcessContinuousWave(uint8_t aArgsLength, char *aArgs[]); 217 Error ProcessGpio(uint8_t aArgsLength, char *aArgs[]); 218 Error ProcessPower(uint8_t aArgsLength, char *aArgs[]); 219 Error ProcessRadio(uint8_t aArgsLength, char *aArgs[]); 220 Error ProcessRepeat(uint8_t aArgsLength, char *aArgs[]); 221 Error ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[]); 222 Error ProcessRawPowerSetting(uint8_t aArgsLength, char *aArgs[]); 223 Error ProcessSend(uint8_t aArgsLength, char *aArgs[]); 224 Error ProcessStart(uint8_t aArgsLength, char *aArgs[]); 225 Error ProcessStats(uint8_t aArgsLength, char *aArgs[]); 226 Error ProcessStop(uint8_t aArgsLength, char *aArgs[]); 227 Error ProcessStream(uint8_t aArgsLength, char *aArgs[]); 228 #if OPENTHREAD_RADIO && !OPENTHREAD_RADIO_CLI 229 Error ProcessEcho(uint8_t aArgsLength, char *aArgs[]); 230 #endif 231 232 Error GetRawPowerSetting(RawPowerSetting &aRawPowerSetting); 233 Error GetPowerSettings(uint8_t aChannel, PowerSettings &aPowerSettings); 234 Error ParseReceiveConfigFormat(const char *aFormat, ReceiveConfig &aConfig); 235 Error RadioReceive(void); 236 Error TransmitPacket(void); 237 void OutputReceivedFrame(const otRadioFrame *aFrame); 238 bool ShouldHandleReceivedFrame(const otRadioFrame &aFrame) const; 239 240 void Output(const char *aFormat, ...); 241 void ResetTxPacket(void); 242 void OutputStats(void); 243 void UpdateTxStats(Error aError); 244 245 static bool IsChannelValid(uint8_t aChannel); 246 247 static const struct Command sCommands[]; 248 249 #if OPENTHREAD_FTD || OPENTHREAD_MTD || (OPENTHREAD_RADIO && OPENTHREAD_RADIO_CLI) 250 enum TxCmd : uint8_t 251 { 252 kTxCmdNone, 253 kTxCmdRepeat, 254 kTxCmdSend, 255 }; 256 257 Stats mStats; 258 259 otRadioFrame *mTxPacket; 260 uint32_t mTxPeriod; 261 uint32_t mTxPackets; 262 uint8_t mChannel; 263 int8_t mTxPower; 264 uint8_t mTxLen; 265 TxCmd mCurTxCmd; 266 bool mIsHeaderUpdated : 1; 267 bool mIsSecurityProcessed : 1; 268 bool mIsTxPacketSet : 1; 269 bool mIsAsyncSend : 1; 270 bool mDiagSendOn : 1; 271 bool mIsSleepOn : 1; 272 #endif 273 274 ReceiveConfig mReceiveConfig; 275 otDiagOutputCallback mOutputCallback; 276 void *mOutputContext; 277 }; 278 279 } // namespace FactoryDiags 280 } // namespace ot 281 282 #endif // #if OPENTHREAD_CONFIG_DIAG_ENABLE 283 284 #endif // FACTORY_DIAGS_HPP_ 285