Esempio n. 1
0
    virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks,
                                   const uavcan::CanFrame* (& pending_tx)[uavcan::MaxCanIfaces],
                                   uavcan::MonotonicTime deadline)
    {
        assert(this);
        //std::cout << "Write/read masks: " << inout_write_iface_mask << "/" << inout_read_iface_mask << std::endl;

        for (unsigned i = 0; i < ifaces.size(); i++)
        {
            ifaces.at(i).pending_tx = (pending_tx[i] == NULL) ? uavcan::CanFrame() : *pending_tx[i];
        }

        if (select_failure)
        {
            return -1;
        }

        const uavcan::uint8_t valid_iface_mask = uavcan::uint8_t((1 << getNumIfaces()) - 1);
        EXPECT_FALSE(inout_masks.write & ~valid_iface_mask);
        EXPECT_FALSE(inout_masks.read & ~valid_iface_mask);

        uavcan::uint8_t out_write_mask = 0;
        uavcan::uint8_t out_read_mask = 0;
        for (unsigned i = 0; i < getNumIfaces(); i++)
        {
            const uavcan::uint8_t mask = uavcan::uint8_t(1 << i);
            if ((inout_masks.write & mask) && ifaces.at(i).writeable)
            {
                out_write_mask |= mask;
            }
            if ((inout_masks.read & mask) && (ifaces.at(i).rx.size() || ifaces.at(i).loopback.size()))
            {
                out_read_mask |= mask;
            }
        }
        inout_masks.write = out_write_mask;
        inout_masks.read = out_read_mask;
        if ((out_write_mask | out_read_mask) == 0)
        {
            const uavcan::MonotonicTime ts = iclock.getMonotonic();
            const uavcan::MonotonicDuration diff = deadline - ts;
            SystemClockMock* const mock = dynamic_cast<SystemClockMock*>(&iclock);
            if (mock)
            {
                if (diff.isPositive())
                {
                    mock->advance(uint64_t(diff.toUSec()));   // Emulating timeout
                }
            }
            else
            {
                if (diff.isPositive())
                {
                    usleep(unsigned(diff.toUSec()));
                }
            }
            return 0;
        }
        return 1;  // This value is not being checked anyway, it just has to be greater than zero
    }
Esempio n. 2
0
int CanIOManager::receive(CanRxFrame& out_frame, MonotonicTime blocking_deadline, CanIOFlags& out_flags)
{
    const uint8_t num_ifaces = getNumIfaces();

    while (true)
    {
        CanSelectMasks masks;
        masks.write = makePendingTxMask();
        masks.read = uint8_t((1 << num_ifaces) - 1);
        {
            const int select_res = callSelect(masks, blocking_deadline);
            if (select_res < 0)
            {
                return -ErrDriver;
            }
        }

        // Write - if buffers are not empty, one frame will be sent for each iface per one receive() call
        for (uint8_t i = 0; i < num_ifaces; i++)
        {
            if (masks.write & (1 << i))
            {
                (void)sendFromTxQueue(i);  // It may fail, we don't care. Requested operation was receive, not send.
            }
        }

        // Read
        for (uint8_t i = 0; i < num_ifaces; i++)
        {
            if (masks.read & (1 << i))
            {
                ICanIface* const iface = driver_.getIface(i);
                if (iface == NULL)
                {
                    UAVCAN_ASSERT(0);   // Nonexistent interface
                    continue;
                }
                const int res = iface->receive(out_frame, out_frame.ts_mono, out_frame.ts_utc, out_flags);
                if (res == 0)
                {
                    UAVCAN_ASSERT(0);   // select() reported that iface has pending RX frames, but receive() returned none
                    continue;
                }
                out_frame.iface_index = i;
                if ((res > 0) && !(out_flags & CanIOFlagLoopback))
                {
                    counters_[i].frames_rx += 1;
                }
                return (res < 0) ? -ErrDriver : res;
            }
        }

        // Timeout checked in the last order - this way we can operate with expired deadline:
        if (sysclock_.getMonotonic() >= blocking_deadline)
        {
            break;
        }
    }
    return 0;
}
Esempio n. 3
0
 void pushRxToAllIfaces(const uavcan::CanFrame& can_frame)
 {
     for (uint8_t i = 0; i < getNumIfaces(); i++)
     {
         ifaces.at(i).pushRx(can_frame);
     }
 }
Esempio n. 4
0
uint8_t CanIOManager::makePendingTxMask() const
{
    uint8_t write_mask = 0;
    for (uint8_t i = 0; i < getNumIfaces(); i++)
    {
        if (!tx_queues_[i]->isEmpty())
        {
            write_mask |= uint8_t(1 << i);
        }
    }
    return write_mask;
}
Esempio n. 5
0
int CanIOManager::send(const CanFrame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline,
                       uint8_t iface_mask, CanTxQueue::Qos qos, CanIOFlags flags)
{
    const uint8_t num_ifaces = getNumIfaces();
    const uint8_t all_ifaces_mask = uint8_t((1U << num_ifaces) - 1);
    iface_mask &= all_ifaces_mask;

    if (blocking_deadline > tx_deadline)
    {
        blocking_deadline = tx_deadline;
    }

    int retval = 0;

    while (true)
    {
        if (iface_mask == 0)
        {
            break;
        }
        CanSelectMasks masks;
        masks.write = iface_mask | makePendingTxMask();
        {
            const int select_res = callSelect(masks, blocking_deadline);
            if (select_res < 0)
            {
                return -ErrDriver;
            }
            UAVCAN_ASSERT(masks.read == 0);
        }

        // Transmission
        for (uint8_t i = 0; i < num_ifaces; i++)
        {
            if (masks.write & (1 << i))
            {
                int res = 0;
                if (iface_mask & (1 << i))
                {
                    if (tx_queues_[i]->topPriorityHigherOrEqual(frame))
                    {
                        res = sendFromTxQueue(i);                 // May return 0 if nothing to transmit (e.g. expired)
                    }
                    if (res <= 0)
                    {
                        res = sendToIface(i, frame, tx_deadline, flags);
                        if (res > 0)
                        {
                            iface_mask &= uint8_t(~(1 << i));     // Mark transmitted
                        }
                    }
                }
                else
                {
                    res = sendFromTxQueue(i);
                }
                if (res > 0)
                {
                    retval++;
                }
            }
        }

        // Timeout. Enqueue the frame if wasn't transmitted and leave.
        const bool timed_out = sysclock_.getMonotonic() >= blocking_deadline;
        if (masks.write == 0 || timed_out)
        {
            if (!timed_out)
            {
                UAVCAN_TRACE("CanIOManager", "Send: Premature timeout in select(), will try again");
                continue;
            }
            for (uint8_t i = 0; i < num_ifaces; i++)
            {
                if (iface_mask & (1 << i))
                {
                    tx_queues_[i]->push(frame, tx_deadline, qos, flags);
                }
            }
            break;
        }
    }
    return retval;
}