int timer_settime()

in FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c [190:291]


int timer_settime( timer_t timerid,
                   int flags,
                   const struct itimerspec * value,
                   struct itimerspec * ovalue )
{
    int iStatus = 0;
    TimerHandle_t xTimerHandle = timerid;
    timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
    TickType_t xNextTimerExpiration = 0, xTimerExpirationPeriod = 0;

    /* Validate the value argument, but only if the timer isn't being disarmed. */
    if( TIMESPEC_IS_NOT_ZERO( value->it_value ) )
    {
        if( ( UTILS_ValidateTimespec( &value->it_interval ) == false ) ||
            ( UTILS_ValidateTimespec( &value->it_value ) == false ) )
        {
            errno = EINVAL;
            iStatus = -1;
        }
    }

    /* Set ovalue, if given. */
    if( ovalue != NULL )
    {
        ( void ) timer_gettime( timerid, ovalue );
    }

    /* Stop the timer if it's currently active. */
    if( ( iStatus == 0 ) && xTimerIsTimerActive( xTimerHandle ) )
    {
        ( void ) xTimerStop( xTimerHandle, portMAX_DELAY );
    }

    /* Only restart the timer if it_value is not zero. */
    if( ( iStatus == 0 ) && TIMESPEC_IS_NOT_ZERO( value->it_value ) )
    {
        /* Convert it_interval to ticks, but only if it_interval is not 0. If
         * it_interval is 0, then the timer is not periodic. */
        if( TIMESPEC_IS_NOT_ZERO( value->it_interval ) )
        {
            ( void ) UTILS_TimespecToTicks( &value->it_interval, &xTimerExpirationPeriod );
        }

        /* Set the new timer period. A non-periodic timer will have its period set
         * to portMAX_DELAY. */
        pxTimer->xTimerPeriod = xTimerExpirationPeriod;

        /* Convert it_value to ticks, but only if it_value is not 0. If it_value
         * is 0, then the timer will remain disarmed. */
        if( TIMESPEC_IS_NOT_ZERO( value->it_value ) )
        {
            /* Absolute timeout. */
            if( ( flags & TIMER_ABSTIME ) == TIMER_ABSTIME )
            {
                struct timespec xCurrentTime = { 0 };

                /* Get current time */
                if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
                {
                    iStatus = EINVAL;
                }
                else
                {
                    iStatus = UTILS_AbsoluteTimespecToDeltaTicks( &value->it_value, &xCurrentTime, &xNextTimerExpiration );
                }

                /* Make sure xNextTimerExpiration is zero in case we got negative time difference */
                if( iStatus != 0 )
                {
                    xNextTimerExpiration = 0;

                    if( iStatus == ETIMEDOUT )
                    {
                        /* Set Status to 0 as absolute time is past is treated as expiry but not an error */
                        iStatus = 0;
                    }
                }
            }
            /* Relative timeout. */
            else
            {
                ( void ) UTILS_TimespecToTicks( &value->it_value, &xNextTimerExpiration );
            }
        }

        /* If xNextTimerExpiration is still 0, that means that it_value specified
         * an absolute timeout in the past. Per POSIX spec, a notification should be
         * triggered immediately. */
        if( xNextTimerExpiration == 0 )
        {
            prvTimerCallback( xTimerHandle );
        }
        else
        {
            /* Set the timer to expire at the it_value, then start it. */
            ( void ) xTimerChangePeriod( xTimerHandle, xNextTimerExpiration, portMAX_DELAY );
            ( void ) xTimerStart( xTimerHandle, xNextTimerExpiration );
        }
    }

    return iStatus;
}