mirror of
https://github.com/espressif/openthread.git
synced 2026-09-04 08:10:11 +00:00
[harness-simulation] add support for RF enclosure simulation (#8092)
This commit adds support for RF enclosure simulation. It can pass Leader 9.2.9, Router 9.2.9 and Router 9.2.10 in Thread Test Harness v56.0 now.
This commit is contained in:
@@ -232,6 +232,18 @@ void otSimSendUartWriteEvent(const uint8_t *aData, uint16_t aLength);
|
||||
*/
|
||||
bool platformRadioIsTransmitPending(void);
|
||||
|
||||
/**
|
||||
* This function parses an environment variable as an unsigned 16-bit integer.
|
||||
*
|
||||
* If the environment variable does not exist, this function does nothing.
|
||||
* If it is not a valid integer, this function will terminate the process with an error message.
|
||||
*
|
||||
* @param[in] aEnvName The name of the environment variable.
|
||||
* @param[out] aValue A pointer to the unsigned 16-bit integer.
|
||||
*
|
||||
*/
|
||||
void parseFromEnvAsUint16(const char *aEnvName, uint16_t *aValue);
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,10 +71,12 @@ enum
|
||||
|
||||
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
|
||||
extern int sSockFd;
|
||||
extern uint16_t sPortBase;
|
||||
extern uint16_t sPortOffset;
|
||||
#else
|
||||
static int sTxFd = -1;
|
||||
static int sRxFd = -1;
|
||||
static uint16_t sPortBase = 9000;
|
||||
static uint16_t sPortOffset = 0;
|
||||
static uint16_t sPort = 0;
|
||||
#endif
|
||||
@@ -166,6 +168,75 @@ static otRadioKeyType sKeyType;
|
||||
|
||||
static int8_t GetRssi(uint16_t aChannel);
|
||||
|
||||
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
|
||||
static uint8_t sDeniedNodeIdsBitVector[(MAX_NETWORK_SIZE + 7) / 8];
|
||||
|
||||
static bool NodeIdFilterIsConnectable(uint16_t aNodeId)
|
||||
{
|
||||
uint16_t index = aNodeId - 1;
|
||||
|
||||
return (sDeniedNodeIdsBitVector[index / 8] & (0x80 >> (index % 8))) == 0;
|
||||
}
|
||||
|
||||
static void NodeIdFilterDeny(uint16_t aNodeId)
|
||||
{
|
||||
uint16_t index = aNodeId - 1;
|
||||
|
||||
sDeniedNodeIdsBitVector[index / 8] |= 0x80 >> (index % 8);
|
||||
}
|
||||
|
||||
static void NodeIdFilterClear(void)
|
||||
{
|
||||
memset(sDeniedNodeIdsBitVector, 0, sizeof(sDeniedNodeIdsBitVector));
|
||||
}
|
||||
|
||||
otError ProcessNodeIdFilter(void *aContext, uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aContext);
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
otEXPECT_ACTION(aArgsLength > 0, error = OT_ERROR_INVALID_COMMAND);
|
||||
|
||||
if (!strcmp(aArgs[0], "clear"))
|
||||
{
|
||||
otEXPECT_ACTION(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
NodeIdFilterClear();
|
||||
}
|
||||
else if (!strcmp(aArgs[0], "deny"))
|
||||
{
|
||||
uint16_t nodeId;
|
||||
char * endptr;
|
||||
|
||||
otEXPECT_ACTION(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
nodeId = (uint16_t)strtol(aArgs[1], &endptr, 0);
|
||||
|
||||
otEXPECT_ACTION(*endptr == '\0', error = OT_ERROR_INVALID_ARGS);
|
||||
otEXPECT_ACTION(1 <= nodeId && nodeId <= MAX_NETWORK_SIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
NodeIdFilterDeny(nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#else
|
||||
otError ProcessNodeIdFilter(void *aContext, uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aContext);
|
||||
OT_UNUSED_VARIABLE(aArgsLength);
|
||||
OT_UNUSED_VARIABLE(aArgs);
|
||||
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
|
||||
|
||||
static bool IsTimeAfterOrEqual(uint32_t aTimeA, uint32_t aTimeB)
|
||||
{
|
||||
return (aTimeA - aTimeB) < (1U << 31);
|
||||
@@ -298,7 +369,7 @@ static void initFds(void)
|
||||
|
||||
otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sTxFd)"));
|
||||
|
||||
sPort = (uint16_t)(9000 + sPortOffset + gNodeId);
|
||||
sPort = (uint16_t)(sPortBase + sPortOffset + gNodeId);
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(sPort);
|
||||
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
@@ -337,7 +408,7 @@ static void initFds(void)
|
||||
}
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons((uint16_t)(9000 + sPortOffset));
|
||||
sockaddr.sin_port = htons((uint16_t)(sPortBase + sPortOffset));
|
||||
sockaddr.sin_addr.s_addr = inet_addr(OT_RADIO_GROUP);
|
||||
|
||||
otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sRxFd)"));
|
||||
@@ -356,24 +427,10 @@ exit:
|
||||
void platformRadioInit(void)
|
||||
{
|
||||
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
|
||||
char *offset;
|
||||
parseFromEnvAsUint16("PORT_BASE", &sPortBase);
|
||||
|
||||
offset = getenv("PORT_OFFSET");
|
||||
|
||||
if (offset)
|
||||
{
|
||||
char *endptr;
|
||||
|
||||
sPortOffset = (uint16_t)strtol(offset, &endptr, 0);
|
||||
|
||||
if (*endptr != '\0')
|
||||
{
|
||||
fprintf(stderr, "Invalid PORT_OFFSET: %s\n", offset);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sPortOffset *= (MAX_NETWORK_SIZE + 1);
|
||||
}
|
||||
parseFromEnvAsUint16("PORT_OFFSET", &sPortOffset);
|
||||
sPortOffset *= (MAX_NETWORK_SIZE + 1);
|
||||
|
||||
initFds();
|
||||
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
|
||||
@@ -829,7 +886,10 @@ void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const
|
||||
|
||||
if (rval > 0)
|
||||
{
|
||||
if (sockaddr.sin_port != htons(sPort))
|
||||
uint16_t srcPort = ntohs(sockaddr.sin_port);
|
||||
uint16_t srcNodeId = srcPort - sPortOffset - sPortBase;
|
||||
|
||||
if (NodeIdFilterIsConnectable(srcNodeId) && srcPort != sPort)
|
||||
{
|
||||
sReceiveFrame.mLength = (uint16_t)(rval - 1);
|
||||
|
||||
@@ -847,7 +907,7 @@ void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
|
||||
if (platformRadioIsTransmitPending())
|
||||
{
|
||||
radioSendMessage(aInstance);
|
||||
@@ -870,7 +930,7 @@ void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFr
|
||||
sockaddr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, OT_RADIO_GROUP, &sockaddr.sin_addr);
|
||||
|
||||
sockaddr.sin_port = htons((uint16_t)(9000 + sPortOffset));
|
||||
sockaddr.sin_port = htons((uint16_t)(sPortBase + sPortOffset));
|
||||
rval =
|
||||
sendto(sTxFd, (const char *)aMessage, 1 + aFrame->mLength, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
||||
|
||||
@@ -1321,3 +1381,21 @@ otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void parseFromEnvAsUint16(const char *aEnvName, uint16_t *aValue)
|
||||
{
|
||||
char *env = getenv(aEnvName);
|
||||
|
||||
if (env)
|
||||
{
|
||||
char *endptr;
|
||||
|
||||
*aValue = (uint16_t)strtol(env, &endptr, 0);
|
||||
|
||||
if (*endptr != '\0')
|
||||
{
|
||||
fprintf(stderr, "Invalid %s: %s\n", aEnvName, env);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ char **gArguments = NULL;
|
||||
|
||||
uint64_t sNow = 0; // microseconds
|
||||
int sSockFd;
|
||||
uint16_t sPortBase = 9000;
|
||||
uint16_t sPortOffset;
|
||||
|
||||
static void handleSignal(int aSignal)
|
||||
@@ -78,7 +79,7 @@ void otSimSendEvent(const struct Event *aEvent)
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
sockaddr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, "127.0.0.1", &sockaddr.sin_addr);
|
||||
sockaddr.sin_port = htons(9000 + sPortOffset);
|
||||
sockaddr.sin_port = htons(sPortBase + sPortOffset);
|
||||
|
||||
rval = sendto(sSockFd, aEvent, offsetof(struct Event, mData) + aEvent->mDataLength, 0, (struct sockaddr *)&sockaddr,
|
||||
sizeof(sockaddr));
|
||||
@@ -176,28 +177,15 @@ otError otPlatUartFlush(void)
|
||||
static void socket_init(void)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
char * offset;
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
sockaddr.sin_family = AF_INET;
|
||||
|
||||
offset = getenv("PORT_OFFSET");
|
||||
parseFromEnvAsUint16("PORT_BASE", &sPortBase);
|
||||
|
||||
if (offset)
|
||||
{
|
||||
char *endptr;
|
||||
parseFromEnvAsUint16("PORT_OFFSET", &sPortOffset);
|
||||
sPortOffset *= (MAX_NETWORK_SIZE + 1);
|
||||
|
||||
sPortOffset = (uint16_t)strtol(offset, &endptr, 0);
|
||||
|
||||
if (*endptr != '\0')
|
||||
{
|
||||
fprintf(stderr, "Invalid PORT_OFFSET: %s\n", offset);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sPortOffset *= (MAX_NETWORK_SIZE + 1);
|
||||
}
|
||||
|
||||
sockaddr.sin_port = htons((uint16_t)(9000 + sPortOffset + gNodeId));
|
||||
sockaddr.sin_port = htons((uint16_t)(sPortBase + sPortOffset + gNodeId));
|
||||
sockaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
sSockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
Reference in New Issue
Block a user