Files
BoilerControlUnit_Firmware/Libs/protocol/openthread/platform-abstraction/efr32/diag.c
GClarkson 9d06f983af Imported more library files
Not compiling currently
2025-04-12 23:37:19 +01:00

474 lines
13 KiB
C

/*
* Copyright (c) 2023, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the OpenThread platform abstraction for the diagnostics.
*
*/
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/time.h>
#ifdef SL_COMPONENT_CATALOG_PRESENT
#include "sl_component_catalog.h"
#endif // SL_COMPONENT_CATALOG_PRESENT
#include <openthread-core-config.h>
#include <utils/code_utils.h>
#include <openthread/cli.h>
#include <openthread/platform/alarm-milli.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/radio.h>
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/logging.hpp"
#include "diag.h"
#include "sl_gpio.h"
#include "sl_hal_gpio.h"
#include "platform-band.h"
#include "platform-efr32.h"
#include "rail_ieee802154.h"
#include "sl_status.h"
#if OPENTHREAD_CONFIG_DIAG_ENABLE
#ifdef SL_COMPONENT_CATALOG_PRESENT
#include "sl_component_catalog.h"
#endif // SL_COMPONENT_CATALOG_PRESENT
#ifdef SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT
#include "sl_rail_util_ant_div.h"
#endif
#define GPIO_PIN_BITMASK 0xFFFFUL
#define GPIO_PORT_BITMASK (0xFFFFUL << 16)
#define GET_GPIO_PIN(x) (x & GPIO_PIN_BITMASK)
#define GET_GPIO_PORT(x) ((x & GPIO_PORT_BITMASK) >> 16)
// To cache the transmit power, so that we don't override it while loading the
// channel config or setting the channel.
static int8_t sTxPower = OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER;
struct PlatformDiagCommand
{
const char *mName;
otError (*mCommand)(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]);
};
// Diagnostics mode variables.
static bool sDiagMode = false;
static otPlatDiagOutputCallback sDiagOutputCallback = NULL;
static void *sDiagCallbackContext = NULL;
static void diagOutput(const char *aFormat, ...)
{
va_list args;
va_start(args, aFormat);
if (sDiagOutputCallback != NULL)
{
sDiagOutputCallback(aFormat, args, sDiagCallbackContext);
}
va_end(args);
}
static void appendErrorResult(otError aError)
{
if (aError != OT_ERROR_NONE)
{
diagOutput("failed\r\nstatus %#x\r\n", aError);
}
}
// *****************************************************************************
// CLI functions
// *****************************************************************************
static otError processAddressMatch(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[])
{
OT_UNUSED_VARIABLE(aInstance);
otError error = OT_ERROR_INVALID_ARGS;
VerifyOrExit(otPlatDiagModeGet(), error = OT_ERROR_INVALID_STATE);
VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS);
if (strcmp(aArgs[0], "enable") == 0)
{
error = otPlatDiagRadioAddressMatch(true);
}
else if (strcmp(aArgs[0], "disable") == 0)
{
error = otPlatDiagRadioAddressMatch(false);
}
exit:
appendErrorResult(error);
return error;
}
static otError processAutoAck(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[])
{
OT_UNUSED_VARIABLE(aInstance);
otError error = OT_ERROR_INVALID_ARGS;
VerifyOrExit(otPlatDiagModeGet(), error = OT_ERROR_INVALID_STATE);
VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS);
if (strcmp(aArgs[0], "enable") == 0)
{
error = otPlatDiagRadioAutoAck(true);
}
else if (strcmp(aArgs[0], "disable") == 0)
{
error = otPlatDiagRadioAutoAck(false);
}
exit:
appendErrorResult(error);
return error;
}
// *****************************************************************************
// Add more platform specific diagnostic's CLI features here.
// *****************************************************************************
const struct PlatformDiagCommand sCommands[] = {
{"addr-match", &processAddressMatch},
{"auto-ack", &processAutoAck},
};
otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_INVALID_COMMAND;
size_t i;
for (i = 0; i < otARRAY_LENGTH(sCommands); i++)
{
if (strcmp(aArgs[0], sCommands[i].mName) == 0)
{
error = sCommands[i].mCommand(aInstance, aArgsLength - 1, aArgsLength > 1 ? &aArgs[1] : NULL);
break;
}
}
return error;
}
// *****************************************************************************
// Implement platform specific diagnostic's APIs.
// *****************************************************************************
void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext)
{
OT_UNUSED_VARIABLE(aInstance);
sDiagOutputCallback = aCallback;
sDiagCallbackContext = aContext;
}
void otPlatDiagModeSet(bool aMode)
{
sDiagMode = aMode;
}
bool otPlatDiagModeGet()
{
return sDiagMode;
}
static RAIL_Status_t startTxStream(RAIL_StreamMode_t aMode)
{
uint16_t txChannel;
RAIL_Status_t status;
SuccessOrExit(status = RAIL_GetChannel(gRailHandle, &txChannel));
#ifdef SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT
RAIL_TxOptions_t txOptions = RAIL_TX_OPTIONS_DEFAULT;
// Translate Tx antenna diversity mode into RAIL Tx Antenna options:
// If enabled, use the currently-selected antenna, otherwise leave
// both options 0 so Tx antenna tracks Rx antenna.
if (sl_rail_util_ant_div_get_tx_antenna_mode() != SL_RAIL_UTIL_ANTENNA_MODE_DISABLED)
{
txOptions |= ((sl_rail_util_ant_div_get_tx_antenna_selected() == SL_RAIL_UTIL_ANTENNA_SELECT_ANTENNA1)
? RAIL_TX_OPTION_ANTENNA0
: RAIL_TX_OPTION_ANTENNA1);
}
status = RAIL_StartTxStreamAlt(gRailHandle, txChannel, aMode, txOptions);
#else // !SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT
status = RAIL_StartTxStream(gRailHandle, txChannel, aMode);
#endif // SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT
exit:
return status;
}
static RAIL_Status_t stopTxStream(void)
{
RAIL_Status_t status;
uint16_t currentChannel;
RAIL_SchedulerInfo_t rxSchedulerInfo = {
.priority = SL_802154_RADIO_PRIO_BACKGROUND_RX_VALUE,
};
SuccessOrExit(status = RAIL_StopTxStream(gRailHandle));
// Since start transmit stream turn off the radio state,
// call the RAIL_StartRx to turn on radio
IgnoreError(RAIL_GetChannel(gRailHandle, &currentChannel));
status = RAIL_StartRx(gRailHandle, currentChannel, &rxSchedulerInfo);
OT_ASSERT(status == RAIL_STATUS_NO_ERROR);
exit:
return status;
}
otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable)
{
OT_UNUSED_VARIABLE(aInstance);
RAIL_Status_t status;
if (aEnable)
{
otLogInfoPlat("Diag CARRIER-WAVE/Tone start");
status = startTxStream(RAIL_STREAM_CARRIER_WAVE);
}
else
{
otLogInfoPlat("Diag CARRIER-WAVE/Tone stop");
status = stopTxStream();
}
return (status != RAIL_STATUS_NO_ERROR ? OT_ERROR_FAILED : OT_ERROR_NONE);
}
otError otPlatDiagRadioTransmitStream(otInstance *aInstance, bool aEnable)
{
OT_UNUSED_VARIABLE(aInstance);
RAIL_Status_t status;
if (aEnable)
{
otLogInfoPlat("Diag Stream PN9 start");
status = startTxStream(RAIL_STREAM_PN9_STREAM);
}
else
{
otLogInfoPlat("Diag Stream stop");
status = stopTxStream();
}
return (status != RAIL_STATUS_NO_ERROR ? OT_ERROR_FAILED : OT_ERROR_NONE);
}
otError otPlatDiagRadioAddressMatch(bool aEnable)
{
RAIL_Status_t status;
otLogInfoPlat("Diag address-match %s", aEnable ? "enable" : "disable");
status = RAIL_IEEE802154_SetPromiscuousMode(gRailHandle, !aEnable);
return (status != RAIL_STATUS_NO_ERROR ? OT_ERROR_FAILED : OT_ERROR_NONE);
}
otError otPlatDiagRadioAutoAck(bool aAutoAckEnabled)
{
otLogInfoPlat("Diag auto-ack %s", aAutoAckEnabled ? "enable" : "disable");
RAIL_PauseRxAutoAck(gRailHandle, !aAutoAckEnabled);
return OT_ERROR_NONE;
}
void otPlatDiagChannelSet(uint8_t aChannel)
{
otError error = OT_ERROR_NONE;
RAIL_Status_t status;
RAIL_SchedulerInfo_t bgRxSchedulerInfo = {
.priority = SL_802154_RADIO_PRIO_BACKGROUND_RX_VALUE,
// sliptime/transaction time is not used for bg rx
};
error = efr32RadioLoadChannelConfig(aChannel, sTxPower);
OT_ASSERT(error == OT_ERROR_NONE);
status = RAIL_StartRx(gRailHandle, aChannel, &bgRxSchedulerInfo);
OT_ASSERT(status == RAIL_STATUS_NO_ERROR);
}
void otPlatDiagTxPowerSet(int8_t aTxPower)
{
RAIL_Status_t status;
// RAIL_SetTxPowerDbm() takes power in units of deci-dBm (0.1dBm)
// Multiply by 10 because aPower is supposed be in units dBm
status = RAIL_SetTxPowerDbm(gRailHandle, ((RAIL_TxPower_t)aTxPower) * 10);
OT_ASSERT(status == RAIL_STATUS_NO_ERROR);
sTxPower = aTxPower;
}
void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aFrame);
OT_UNUSED_VARIABLE(aError);
}
void otPlatDiagAlarmCallback(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
}
static otError getGpioPortAndPin(uint32_t aGpio, uint16_t *aPort, uint16_t *aPin)
{
otError error = OT_ERROR_NONE;
*aPort = GET_GPIO_PORT(aGpio);
*aPin = GET_GPIO_PIN(aGpio);
#if defined(SL_CATALOG_GPIO_PRESENT)
if (*aPort > SL_HAL_GPIO_PORT_MAX || *aPin > SL_HAL_GPIO_PIN_MAX)
#else
if (*aPort > GPIO_PORT_MAX || *aPin > GPIO_PIN_MAX)
#endif
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
exit:
return error;
}
otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue)
{
otError error = OT_ERROR_NONE;
uint16_t port;
uint16_t pin;
SuccessOrExit(error = getGpioPortAndPin(aGpio, &port, &pin));
sl_gpio_t gpio;
gpio.port = (uint8_t)port;
gpio.pin = (uint8_t)pin;
if (aValue)
{
VerifyOrExit(sl_gpio_set_pin(&gpio) == SL_STATUS_OK, error = OT_ERROR_INVALID_ARGS);
}
else
{
VerifyOrExit(sl_gpio_clear_pin(&gpio) == SL_STATUS_OK, error = OT_ERROR_INVALID_ARGS);
}
exit:
return error;
}
otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue)
{
otError error = OT_ERROR_NONE;
uint16_t port;
uint16_t pin;
SuccessOrExit(error = getGpioPortAndPin(aGpio, &port, &pin));
sl_gpio_t gpio;
gpio.port = (uint8_t)port;
gpio.pin = (uint8_t)pin;
VerifyOrExit(sl_gpio_get_pin_input(&gpio, aValue) == SL_STATUS_OK, error = OT_ERROR_INVALID_ARGS);
exit:
return error;
}
otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode)
{
otError error = OT_ERROR_NONE;
uint16_t port;
uint16_t pin;
sl_gpio_mode_t mode;
SuccessOrExit(error = getGpioPortAndPin(aGpio, &port, &pin));
mode = (aMode == OT_GPIO_MODE_INPUT) ? SL_GPIO_MODE_INPUT : SL_GPIO_MODE_PUSH_PULL;
sl_gpio_t gpio;
gpio.port = (uint8_t)port;
gpio.pin = (uint8_t)pin;
error = sl_gpio_set_pin_mode(&gpio, mode, 0 /*out*/);
// Convert to otError.
VerifyOrExit(error == SL_STATUS_OK,
error = (error == SL_STATUS_INVALID_STATE ? OT_ERROR_INVALID_STATE : OT_ERROR_INVALID_ARGS));
exit:
return error;
}
otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode)
{
otError error = OT_ERROR_NONE;
uint16_t port;
uint16_t pin;
sl_gpio_mode_t mode;
SuccessOrExit(error = getGpioPortAndPin(aGpio, &port, &pin));
sl_gpio_t gpio;
sl_gpio_pin_config_t pin_config;
gpio.port = (uint8_t)port;
gpio.pin = (uint8_t)pin;
VerifyOrExit(sl_gpio_get_pin_config(&gpio, &pin_config) == SL_STATUS_OK, error = OT_ERROR_INVALID_ARGS);
mode = pin_config.mode;
*aMode = (mode == SL_GPIO_MODE_INPUT) ? OT_GPIO_MODE_INPUT : OT_GPIO_MODE_OUTPUT;
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE