Skip to content

Commit

Permalink
Merge pull request #24 from REVrobotics/fix/repeat-frames
Browse files Browse the repository at this point in the history
Fix repeat frames
  • Loading branch information
LandryNorris committed Mar 25, 2024
2 parents d857994 + 6a79c2e commit 8316a1f
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 13 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,41 @@

This repository is for the CANBridge software that is run on non-roboRIO platforms.

## Behavior

When sending a frame with a given interval, the behavior when
setting a new interval is as follows:

The first time a frame is scheduled with an interval, it
will be sent at the next available time. The next instance
of the same frame id will be sent after that interval, even
if the interval has changed.

See the following pseudo-example:

```
sendMessage(frame, 5000)
delay(1000)
updateFrameData(frame)
sendMessage(frame, 1000)
delay(500)
updateFrameData(frame)
sendMessage(frame, 2000)
```

In this case, the first frame will be scheduled immediately,
the second will be scheduled 5 seconds later, and after that,
subsequent frames will be scheduled every 2 seconds. Note
that any change to the data in the second call will not be
sent, meaning the second call is essentially a no-op if a
new call with different data is sent before the previous
interval is up. Sending a frame with an interval of -1
will cancel the repeat, and not send the frame. Sending with
an interval of 0 will schedule the new frame once, then stop
repeating.

## Build Requirements

1. Git
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ class CandleWinUSBDeviceThread :public DriverDeviceThread {
void stopRepeatedMessage(uint32_t messageId) {
for (int i = 0; i < m_sendQueue.size(); i++) {
detail::CANThreadSendQueueElement el = m_sendQueue.front();
m_sendQueue.pop();
if (el.m_msg.GetMessageId() != messageId) m_sendQueue.push(el);
m_sendQueue.pop_front();
if (el.m_msg.GetMessageId() != messageId) m_sendQueue.push_back(el);
}
}

Expand Down Expand Up @@ -204,23 +204,23 @@ class CandleWinUSBDeviceThread :public DriverDeviceThread {
detail::CANThreadSendQueueElement el = m_sendQueue.front();
if (el.m_intervalMs == -1) {
while(m_sendQueue.size() > 0) {
m_sendQueue.pop();
m_sendQueue.pop_front();
}
continue;
}

auto now = std::chrono::steady_clock::now();

m_sendQueue.pop();
m_sendQueue.pop_front();
if (WriteMessages(el, now)) {

// Return to end of queue if repeated
if (el.m_intervalMs > 0 ) {
el.m_prevTimestamp = now;
m_sendQueue.push(el);
m_sendQueue.push_back(el);
}
} else {
m_sendQueue.push(el);
m_sendQueue.push_back(el);
}
}
}
Expand Down
27 changes: 22 additions & 5 deletions src/main/native/include/rev/Drivers/DriverDeviceThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,26 @@ class DriverDeviceThread {
}
}

detail::CANThreadSendQueueElement* findFirstMatchingId(int targetId) {
for (auto& element : m_sendQueue) {
if (element.m_msg.GetMessageId() == targetId) {
return &element;
}
}
return nullptr; // If no matching element found
}

bool EnqueueMessage(const CANMessage& msg, int32_t timeIntervalMs) {
std::lock_guard<std::mutex> lock(m_writeMutex);
m_sendQueue.push(detail::CANThreadSendQueueElement(msg, timeIntervalMs));

detail::CANThreadSendQueueElement* existing = findFirstMatchingId(msg.GetMessageId());

if(existing) {
existing->m_intervalMs = timeIntervalMs;
existing->m_msg = msg;
} else {
m_sendQueue.push_back(detail::CANThreadSendQueueElement(msg, timeIntervalMs));
}

// TODO: Limit the max queue size
return true;
Expand Down Expand Up @@ -169,7 +186,7 @@ class DriverDeviceThread {
int m_statusErrCount = 0;
CANStatus m_threadStatus = CANStatus::kOk;

std::queue<detail::CANThreadSendQueueElement> m_sendQueue;
std::deque<detail::CANThreadSendQueueElement> m_sendQueue;
std::map<uint32_t, std::shared_ptr<CANMessage>> m_readStore;
std::map<uint32_t, std::unique_ptr<CANStreamHandle>> m_readStream; // (id, mask), max size, message buffer

Expand Down Expand Up @@ -200,20 +217,20 @@ class DriverDeviceThread {
for (size_t i=0;i<queueSize;i++) {
detail::CANThreadSendQueueElement el = m_sendQueue.front();
if (el.m_intervalMs == -1) {
m_sendQueue.pop();
m_sendQueue.pop_front();
continue;
}

auto now = std::chrono::steady_clock::now();

// Don't pop queue if send fails
if (WriteMessages(el, now)) {
m_sendQueue.pop();
m_sendQueue.pop_front();

// Return to end of queue if repeated
if (el.m_intervalMs > 0 ) {
el.m_prevTimestamp = now;
m_sendQueue.push(el);
m_sendQueue.push_back(el);
}
} else {
// Wait a little bit before trying again
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ class SerialDeviceThread : public DriverDeviceThread {
std::lock_guard<std::mutex> lock(m_writeMutex);
if (m_sendQueue.size() > 0) {
detail::CANThreadSendQueueElement el = m_sendQueue.front();
m_sendQueue.pop();
m_sendQueue.pop_front();
if (el.m_intervalMs == -1) {
continue;
}
Expand All @@ -285,7 +285,7 @@ class SerialDeviceThread : public DriverDeviceThread {
if (el.m_intervalMs > 0 ) {
el.m_prevTimestamp = now;

m_sendQueue.push(el);
m_sendQueue.push_back(el);
}
doRead = true;
}
Expand Down

0 comments on commit 8316a1f

Please sign in to comment.