You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
11 KiB
C
332 lines
11 KiB
C
/***************************************************************************//**
|
|
* @file
|
|
* @brief Source file for RAIL Ram Modem Reconfiguration functionality
|
|
*******************************************************************************
|
|
* # License
|
|
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
|
|
*******************************************************************************
|
|
*
|
|
* SPDX-License-Identifier: Zlib
|
|
*
|
|
* The licensor of this software is Silicon Laboratories Inc.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
|
|
#include "rail.h"
|
|
#include "em_common.h"
|
|
#include "em_core.h"
|
|
#include "em_device.h"
|
|
#include "sli_rail_util_callbacks.h"
|
|
|
|
#include "railapp_rmr.h"
|
|
#include "railapp_malloc.h"
|
|
#include "app_common.h"
|
|
#include "response_print.h"
|
|
|
|
typedef struct RMR_State{
|
|
uint32_t phyInfo[RMR_PHY_INFO_LEN];
|
|
uint8_t irCalConfig[RMR_IRCAL_LEN];
|
|
uint32_t modemConfigEntry[RMR_MODEM_CONFIG_LEN];
|
|
RAIL_FrameType_t frameTypeConfig;
|
|
uint16_t frameLenList[RMR_FRAME_LENGTH_LIST_LEN];
|
|
uint32_t frameCodingTable[RMR_FRAME_CODING_TABLE_LEN];
|
|
RAIL_ChannelConfigEntryAttr_t generatedEntryAttr;
|
|
RAIL_ChannelConfigEntry_t generatedChannels[1];
|
|
__ALIGNED(4) uint8_t convDecodeBuffer[RMR_CONV_DECODE_BUFFER_LEN];
|
|
RAIL_ChannelConfig_t channelConfig;
|
|
#if (_SILICON_LABS_32B_SERIES_2_CONFIG >= 3)
|
|
uint8_t dcdcRetimingConfig[RMR_DCDC_RETIMING_LEN];
|
|
#endif
|
|
#if (_SILICON_LABS_32B_SERIES_2_CONFIG >= 2)
|
|
uint8_t hfxoRetimingConfig[RMR_HFXO_RETIMING_LEN];
|
|
#endif
|
|
} RMR_State_t;
|
|
|
|
static RMR_State_t *rmrState = NULL;
|
|
|
|
// Internal commands
|
|
RAIL_Status_t Rmr_writeRmrStructure(RAIL_RMR_StructureIndex_t structure, uint16_t offset, uint8_t count, uint8_t *dataPtr);
|
|
RAIL_Status_t Rmr_updateConfigurationPointer(uint8_t structToModify, uint16_t offset, uint8_t structToPointTo);
|
|
RAIL_Status_t Rmr_reconfigureModem(RAIL_Handle_t railHandle);
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Ram Modem Reconfiguration Commands
|
|
//-----------------------------------------------------------------------------
|
|
RAIL_Status_t Rmr_updateConfigurationPointer(uint8_t structToModify, uint16_t offset, uint8_t structToPointTo)
|
|
{
|
|
uint32_t structPointer = 0u; // NULL
|
|
// First get the addres of the structure we are trying to reference
|
|
switch (structToPointTo) {
|
|
case (RMR_STRUCT_PHY_INFO): {
|
|
structPointer = (uint32_t)&(rmrState->phyInfo);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_IRCAL_CONFIG): {
|
|
structPointer = (uint32_t)&(rmrState->irCalConfig);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_FRAME_TYPE_CONFIG): {
|
|
structPointer = (uint32_t)&(rmrState->frameTypeConfig);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_FRAME_LENGTH_LIST): {
|
|
structPointer = (uint32_t)&(rmrState->frameLenList);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_FRAME_CODING_TABLE): {
|
|
structPointer = (uint32_t)&(rmrState->frameCodingTable);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_CONV_DECODE_BUFFER): {
|
|
structPointer = (uint32_t)&(rmrState->convDecodeBuffer);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_NULL): {
|
|
structPointer = 0u; // NULL
|
|
break;
|
|
}
|
|
#if (_SILICON_LABS_32B_SERIES_2_CONFIG >= 3)
|
|
case (RMR_STRUCT_DCDC_RETIMING_CONFIG): {
|
|
structPointer = (uint32_t)&(rmrState->dcdcRetimingConfig);
|
|
break;
|
|
}
|
|
#endif
|
|
#if (_SILICON_LABS_32B_SERIES_2_CONFIG >= 2)
|
|
case (RMR_STRUCT_HFXO_RETIMING_CONFIG): {
|
|
structPointer = (uint32_t)&(rmrState->hfxoRetimingConfig);
|
|
break;
|
|
}
|
|
#endif
|
|
default: {
|
|
// Error, unrecognized structure
|
|
return RAIL_STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
switch (structToModify) {
|
|
case (RMR_STRUCT_MODEM_CONFIG): {
|
|
if (offset >= RMR_MODEM_CONFIG_LEN) {
|
|
return RAIL_STATUS_INVALID_PARAMETER;
|
|
}
|
|
rmrState->modemConfigEntry[offset] = structPointer;
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_PHY_INFO): {
|
|
if (offset >= RMR_PHY_INFO_LEN) {
|
|
return RAIL_STATUS_INVALID_PARAMETER;
|
|
}
|
|
rmrState->phyInfo[offset] = structPointer;
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_FRAME_TYPE_CONFIG): {
|
|
if (offset != 0) {
|
|
return RAIL_STATUS_INVALID_PARAMETER;
|
|
}
|
|
rmrState->frameTypeConfig.frameLen = (uint16_t *)structPointer;
|
|
break;
|
|
}
|
|
default: {
|
|
// Error unrecognized structure
|
|
return RAIL_STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
return RAIL_STATUS_NO_ERROR;
|
|
}
|
|
|
|
RAIL_Status_t Rmr_reconfigureModem(RAIL_Handle_t railHandle)
|
|
{
|
|
RAIL_RadioState_t currentState = RAIL_GetRadioState(railHandle);
|
|
if (currentState != RAIL_RF_STATE_IDLE) {
|
|
return RAIL_STATUS_INVALID_STATE;
|
|
}
|
|
disableIncompatibleProtocols(RAIL_PTI_PROTOCOL_CUSTOM);
|
|
|
|
// Always include frame type length functionality when using RMR or config
|
|
// channels won't work for frame type based lengths.
|
|
RAIL_IncludeFrameTypeLength(railHandle);
|
|
|
|
// Configure with the downloaded channel configuration.
|
|
RAIL_ConfigChannels(railHandle, &rmrState->channelConfig, &sli_rail_util_on_channel_config_change);
|
|
|
|
// Make sure that we stay in idle after the reconfiguration.
|
|
RAIL_Idle(railHandle, RAIL_IDLE_FORCE_SHUTDOWN_CLEAR_FLAGS, false);
|
|
|
|
return RAIL_STATUS_NO_ERROR;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// RMR CI Commands
|
|
//-----------------------------------------------------------------------------
|
|
RAIL_Status_t Rmr_writeRmrStructure(RAIL_RMR_StructureIndex_t structure, uint16_t offset, uint8_t count, uint8_t *dataPtr)
|
|
{
|
|
uint8_t *targetStruct;
|
|
uint32_t size;
|
|
switch (structure) {
|
|
case (RMR_STRUCT_PHY_INFO): {
|
|
size = sizeof(rmrState->phyInfo);
|
|
targetStruct = (uint8_t *) &(rmrState->phyInfo);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_IRCAL_CONFIG): {
|
|
size = sizeof(rmrState->irCalConfig);
|
|
targetStruct = (uint8_t *) &(rmrState->irCalConfig);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_MODEM_CONFIG): {
|
|
size = sizeof(rmrState->modemConfigEntry);
|
|
targetStruct = (uint8_t *) &(rmrState->modemConfigEntry);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_FRAME_TYPE_CONFIG): {
|
|
size = sizeof(rmrState->frameTypeConfig);
|
|
targetStruct = (uint8_t *) &(rmrState->frameTypeConfig);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_FRAME_LENGTH_LIST): {
|
|
size = sizeof(rmrState->frameLenList);
|
|
targetStruct = (uint8_t *) &(rmrState->frameLenList);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_FRAME_CODING_TABLE): {
|
|
size = RMR_FRAME_CODING_TABLE_LEN * sizeof(uint32_t);
|
|
targetStruct = (uint8_t *) &(rmrState->frameCodingTable);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_CHANNEL_CONFIG_ATTRIBUTES): {
|
|
size = sizeof(rmrState->generatedEntryAttr);
|
|
targetStruct = (uint8_t *) &(rmrState->generatedEntryAttr);
|
|
break;
|
|
}
|
|
case (RMR_STRUCT_CHANNEL_CONFIG_ENTRY): {
|
|
size = sizeof(rmrState->generatedChannels);
|
|
targetStruct = (uint8_t *) &(rmrState->generatedChannels);
|
|
break;
|
|
}
|
|
#if (_SILICON_LABS_32B_SERIES_2_CONFIG >= 3)
|
|
case (RMR_STRUCT_DCDC_RETIMING_CONFIG): {
|
|
size = sizeof(rmrState->dcdcRetimingConfig);
|
|
targetStruct = (uint8_t *) &(rmrState->dcdcRetimingConfig);
|
|
break;
|
|
}
|
|
#endif
|
|
#if (_SILICON_LABS_32B_SERIES_2_CONFIG >= 2)
|
|
case (RMR_STRUCT_HFXO_RETIMING_CONFIG): {
|
|
size = sizeof(rmrState->hfxoRetimingConfig);
|
|
targetStruct = (uint8_t *) &(rmrState->hfxoRetimingConfig);
|
|
break;
|
|
}
|
|
#endif
|
|
default: {
|
|
return RAIL_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
// Check that we are not writing out of bounds
|
|
if ((offset + count) > size) {
|
|
return RAIL_STATUS_INVALID_PARAMETER;
|
|
}
|
|
targetStruct += offset;
|
|
while (count-- != 0u) {
|
|
*targetStruct = *dataPtr;
|
|
targetStruct++;
|
|
dataPtr++;
|
|
}
|
|
return RAIL_STATUS_NO_ERROR;
|
|
}
|
|
|
|
static bool rmrInit(sl_cli_command_arg_t *args)
|
|
{
|
|
if (rmrState == NULL) {
|
|
rmrState = RAILAPP_Malloc(sizeof(RMR_State_t));
|
|
if (rmrState == NULL) {
|
|
responsePrintError(sl_cli_get_command_string(args, 0), 0x86, "Error allocating RMR memory.");
|
|
return false;
|
|
}
|
|
rmrState->channelConfig.phyConfigBase = &(rmrState->modemConfigEntry[0]);
|
|
rmrState->channelConfig.phyConfigDeltaSubtract = NULL;
|
|
rmrState->channelConfig.configs = rmrState->generatedChannels;
|
|
rmrState->channelConfig.length = 1;
|
|
rmrState->channelConfig.signature = 0U;
|
|
rmrState->generatedChannels[0].phyConfigDeltaAdd = NULL;
|
|
rmrState->generatedChannels[0].attr = &rmrState->generatedEntryAttr;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CI_writeRmrStructure(sl_cli_command_arg_t *args)
|
|
{
|
|
uint8_t count = sl_cli_get_argument_uint8(args, RMR_CI_COUNT);
|
|
uint8_t bufferedData[RMR_ARGUMENT_BUFFER_SIZE];
|
|
if (!rmrInit(args)) {
|
|
return;
|
|
}
|
|
if (sl_cli_get_argument_count(args) != (count + RMR_CI_DATA_START)) {
|
|
responsePrintError(sl_cli_get_command_string(args, 0), 0x80, "Argument count does not match number of arguments.");
|
|
return;
|
|
}
|
|
if (count > RMR_ARGUMENT_BUFFER_SIZE) {
|
|
responsePrintError(sl_cli_get_command_string(args, 0), 0x81, "Number of arguments greater than local buffer.");
|
|
return;
|
|
}
|
|
RAIL_RMR_StructureIndex_t structure = sl_cli_get_argument_uint8(args, RMR_CI_RMR_STRUCTURE);
|
|
uint16_t offset = sl_cli_get_argument_uint16(args, RMR_CI_OFFSET);
|
|
for (uint8_t i = 0; i < count; i++) {
|
|
bufferedData[i] = sl_cli_get_argument_uint8(args, RMR_CI_DATA_START + i);
|
|
}
|
|
if (Rmr_writeRmrStructure(structure, offset, count, bufferedData) != RAIL_STATUS_NO_ERROR) {
|
|
responsePrintError(sl_cli_get_command_string(args, 0), 0x82, "Error writing to structure.");
|
|
return;
|
|
}
|
|
responsePrint(sl_cli_get_command_string(args, 0), "CommandStatus:Success");
|
|
return;
|
|
}
|
|
|
|
void CI_updateConfigurationPointer(sl_cli_command_arg_t *args)
|
|
{
|
|
if (!rmrInit(args)) {
|
|
return;
|
|
}
|
|
if (sl_cli_get_argument_count(args) != 3) {
|
|
responsePrintError(sl_cli_get_command_string(args, 0), 0x83, "Incorrect number of arguments");
|
|
return;
|
|
}
|
|
uint8_t structure = sl_cli_get_argument_uint8(args, 0);
|
|
uint16_t location = sl_cli_get_argument_uint16(args, 1);
|
|
uint8_t pointer = sl_cli_get_argument_uint8(args, 2);
|
|
if (Rmr_updateConfigurationPointer(structure, location, pointer) != RAIL_STATUS_NO_ERROR) {
|
|
responsePrintError(sl_cli_get_command_string(args, 0), 0x84, "Error updating structure");
|
|
return;
|
|
}
|
|
responsePrint(sl_cli_get_command_string(args, 0), "CommandStatus:Success");
|
|
}
|
|
|
|
void CI_reconfigureModem(sl_cli_command_arg_t *args)
|
|
{
|
|
if (!rmrInit(args)) {
|
|
return;
|
|
}
|
|
if (Rmr_reconfigureModem(railHandle) == RAIL_STATUS_NO_ERROR) {
|
|
responsePrint(sl_cli_get_command_string(args, 0), "CommandStatus:Success");
|
|
} else {
|
|
responsePrintError(sl_cli_get_command_string(args, 0), 0x85, "Need to be in Idle radio state for this command");
|
|
}
|
|
}
|