[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:
Jiachen Dong
2022-09-14 14:31:06 -07:00
committed by GitHub
parent 436bde84f5
commit a0c4ede86d
15 changed files with 302 additions and 70 deletions
@@ -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
/**
+100 -22
View File
@@ -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);