blob: 7af1e327c74fd0cd64b4a380f2cd1c81b69dc045 [file] [log] [blame]
/*
* Copyright (c) 2016, 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
* @brief
* This file includes the platform-specific initializers.
*/
#include "platform-posix.h"
#include <assert.h>
#include <errno.h>
#include <libgen.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <openthread/tasklet.h>
#include <openthread/platform/alarm-milli.h>
uint64_t gNodeId = 0;
extern bool gPlatformPseudoResetWasRequested;
static void PrintUsage(const char *aArg0)
{
fprintf(stderr, "Syntax:\n %s [-s TimeSpeedUpFactor] {NodeId|Device DeviceConfig|Command CommandArgs}\n", aArg0);
exit(EXIT_FAILURE);
}
void otSysInit(int aArgCount, char *aArgVector[])
{
int i;
uint32_t speedUpFactor = 1;
char * endptr;
const char *radioFile = NULL;
const char *radioConfig = "";
if (gPlatformPseudoResetWasRequested)
{
gPlatformPseudoResetWasRequested = false;
return;
}
if (aArgCount < 2)
{
PrintUsage(aArgVector[0]);
}
i = 1;
if (!strcmp(aArgVector[i], "-s"))
{
++i;
speedUpFactor = (uint32_t)strtol(aArgVector[i], &endptr, 0);
if (*endptr != '\0' || speedUpFactor == 0)
{
fprintf(stderr, "Invalid value for TimerSpeedUpFactor: %s\n", aArgVector[i]);
exit(EXIT_FAILURE);
}
++i;
}
if (i >= aArgCount)
{
PrintUsage(aArgVector[0]);
}
radioFile = aArgVector[i];
if (i + 1 < aArgCount)
{
radioConfig = aArgVector[i + 1];
}
platformLoggingInit(basename(aArgVector[0]));
#if OPENTHREAD_POSIX_VIRTUAL_TIME
otSimInit();
#endif
platformAlarmInit(speedUpFactor);
platformRadioInit(radioFile, radioConfig);
platformRandomInit();
#if OPENTHREAD_ENABLE_PLATFORM_UDP
platformUdpInit();
#endif
}
bool otSysPseudoResetWasRequested(void)
{
return gPlatformPseudoResetWasRequested;
}
void otSysDeinit(void)
{
#if OPENTHREAD_POSIX_VIRTUAL_TIME
otSimDeinit();
#endif
platformRadioDeinit();
}
#if OPENTHREAD_POSIX_VIRTUAL_TIME
/**
* This function try selecting the given file descriptors in nonblocking mode.
*
* @param[inout] aReadFdSet A pointer to the read file descriptors.
* @param[inout] aWriteFdSet A pointer to the write file descriptors.
* @param[inout] aErrorFdSet A pointer to the error file descriptors.
* @param[in] aMaxFd The max file descriptor.
*
* @returns The value returned from select().
*
*/
static int trySelect(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int aMaxFd)
{
struct timeval timeout = {0, 0};
fd_set originReadFdSet = *aReadFdSet;
fd_set originWriteFdSet = *aWriteFdSet;
fd_set originErrorFdSet = *aErrorFdSet;
int rval;
rval = select(aMaxFd + 1, aReadFdSet, aWriteFdSet, aErrorFdSet, &timeout);
if (rval == 0)
{
*aReadFdSet = originReadFdSet;
*aWriteFdSet = originWriteFdSet;
*aErrorFdSet = originErrorFdSet;
}
return rval;
}
#endif // OPENTHREAD_POSIX_VIRTUAL_TIME
void otSysProcessDrivers(otInstance *aInstance)
{
fd_set readFdSet;
fd_set writeFdSet;
fd_set errorFdSet;
struct timeval timeout;
int maxFd = -1;
int rval;
FD_ZERO(&readFdSet);
FD_ZERO(&writeFdSet);
FD_ZERO(&errorFdSet);
platformAlarmUpdateTimeout(&timeout);
platformUartUpdateFdSet(&readFdSet, &writeFdSet, &errorFdSet, &maxFd);
#if OPENTHREAD_ENABLE_PLATFORM_UDP
platformUdpUpdateFdSet(aInstance, &readFdSet, &maxFd);
#endif
#if OPENTHREAD_POSIX_VIRTUAL_TIME
otSimUpdateFdSet(&readFdSet, &writeFdSet, &errorFdSet, &maxFd, &timeout);
#else
platformRadioUpdateFdSet(&readFdSet, &writeFdSet, &maxFd, &timeout);
#endif
if (otTaskletsArePending(aInstance))
{
timeout.tv_sec = 0;
timeout.tv_usec = 0;
}
#if OPENTHREAD_POSIX_VIRTUAL_TIME
if (timerisset(&timeout))
{
// Make sure there are no data ready in UART
rval = trySelect(&readFdSet, &writeFdSet, &errorFdSet, maxFd);
if (rval == 0)
{
bool noWrite = true;
// If there are write requests, the device is supposed to wake soon
for (int i = 0; i < maxFd + 1; ++i)
{
if (FD_ISSET(i, &writeFdSet))
{
noWrite = false;
break;
}
}
if (noWrite)
{
otSimSendSleepEvent(&timeout);
}
rval = select(maxFd + 1, &readFdSet, &writeFdSet, &errorFdSet, NULL);
assert(rval > 0);
}
}
else
#endif
{
rval = select(maxFd + 1, &readFdSet, &writeFdSet, &errorFdSet, &timeout);
}
if ((rval < 0) && (errno != EINTR))
{
perror("select");
exit(EXIT_FAILURE);
}
#if OPENTHREAD_POSIX_VIRTUAL_TIME
otSimProcess(aInstance, &readFdSet, &writeFdSet, &errorFdSet);
#else
platformRadioProcess(aInstance, &readFdSet, &writeFdSet);
#endif
platformUartProcess(&readFdSet, &writeFdSet, &errorFdSet);
platformAlarmProcess(aInstance);
#if OPENTHREAD_ENABLE_PLATFORM_UDP
platformUdpProcess(aInstance, &readFdSet);
#endif
}