Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A couple of fixes before everyone uses the examples #8

Merged
merged 20 commits into from Apr 1, 2019
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e5de4fc
Replace faulty loop with volatile flag
LRstudentHU Mar 27, 2019
fd236e6
Initial idea for send a frame to an external system
LRstudentHU Mar 28, 2019
89650d9
WIP
LRstudentHU Mar 28, 2019
a55419c
Implemented basic extended frame support
LRstudentHU Mar 28, 2019
8f1050a
Fix docs
LRstudentHU Mar 28, 2019
cf1198b
Only distribute internally when needed
LRstudentHU Mar 29, 2019
d002fa3
Fix a bug where the size of the packet is always sizeof(uint8_t); red…
LRstudentHU Mar 29, 2019
ead96b5
Fix constructor name
LRstudentHU Mar 31, 2019
51affc9
bugfix base_module and static cast fix
itzandroidtab Apr 1, 2019
5a2a160
bugfix sequence total shift the same as sequence id
itzandroidtab Apr 1, 2019
4052e60
changed all the memcpy to byte for byte for all transfers beneath 8 b…
itzandroidtab Apr 1, 2019
dfdf4b0
made led module compile and inverted the button
itzandroidtab Apr 1, 2019
eae9f92
made the controller module compile
itzandroidtab Apr 1, 2019
7571853
bugfix for not updating the data and added extended mode to the write
itzandroidtab Apr 1, 2019
c7b9fe3
Merge branch 'feature-external_comm_frames' of https://github.com/R2D…
LRstudentHU Apr 1, 2019
84cc1d3
Fix CAN frame table
LRstudentHU Apr 1, 2019
3d51508
removed all memcpy since it breaks some functionality at the momen
itzandroidtab Apr 1, 2019
94057c2
removed memcpy comment
itzandroidtab Apr 1, 2019
33742fc
changed indent of comment
itzandroidtab Apr 1, 2019
7f3c133
added quotes and added comment back to loop
itzandroidtab Apr 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -172,7 +172,7 @@ Directly connecting the Due to these types of components will likely damage or d

### Frame structure
A CAN frame within the project has the following structure:
[![CAN-frame-1.png](https://i.postimg.cc/RFgPWWKV/CAN-frame-1.png)](https://postimg.cc/njQK5c36)
[![CAN-frame-1-1.png](https://i.postimg.cc/9fMyyFJb/CAN-frame-1-1.png)](https://postimg.cc/18kgQPxV)

Explanation:
- ID: the priority (channel) of the frame. Lower value = higher priority.
Expand Down
49 changes: 37 additions & 12 deletions code/headers/base_comm.hpp
Expand Up @@ -94,7 +94,7 @@ namespace r2d2 {
* @param buffer
* @param prio
*/
virtual void send_impl(const frame_type &type, const uint8_t data[], const priority prio) = 0;
virtual void send_impl(const frame_type &type, const uint8_t data[], const size_t length, const priority prio) = 0;

public:
/**
Expand All @@ -116,29 +116,54 @@ namespace r2d2 {
template<
typename T,
typename = std::enable_if_t<
is_suitable_frame_v<T> && !is_extended_frame_v<T>
is_suitable_frame_v<T>
>
>
void send(const T &data, const priority prio = priority::NORMAL) {
uint8_t buffer[8] = {};

memcpy(
(void *) buffer,
(const void *) &data,
sizeof(T)
);

send_impl(
static_cast<frame_type>(frame_type_v<T>), buffer, prio
static_cast<frame_type>(frame_type_v<T>),
reinterpret_cast<const uint8_t *>(&data),
sizeof(T),
prio
);
}

/**
* Send the given data to an external system
* with the given priority.
*
* @tparam T
* @param id
* @param data
* @param prio
*/
template<
typename T,
typename = std::enable_if_t<
is_suitable_frame_v<T>
>
>
void send(const external_id_s &id, const T &data, const priority prio = priority::NORMAL) {
// No {} needed, since all fields are filled.
// Adding it will cause a call to memset
frame_external_s frame;

for(uint_fast8_t i = 0; i < sizeof(T); i++){
LRstudentHU marked this conversation as resolved.
Show resolved Hide resolved
frame.data[i] = data[i];
}

frame.length = sizeof(T);
frame.id = id;

send(frame, prio);
}

/**
* Listen for the given list of packets.
*
* @param listen_for
*/
void listen_for_frames(const std::array<frame_id, 8> listen_for) {
void listen_for_frames(std::array<frame_id, 8> listen_for /* Copy to allow move */) {
this->listen_for = listen_for;

// Sort to enable binary search
Expand Down
2 changes: 1 addition & 1 deletion code/headers/base_module.hpp
Expand Up @@ -15,7 +15,7 @@ namespace r2d2 {
/**
* @param comm
*/
explicit module_c(base_comm_c &comm)
explicit base_module_c(base_comm_c &comm)
: comm(comm) { }

/**
Expand Down
7 changes: 4 additions & 3 deletions code/headers/can.hpp
Expand Up @@ -343,7 +343,7 @@ namespace r2d2::can_bus {
frame.mode = (id >> 25) & 0x01;
frame.frame_type = (id >> 10) & 0xFF;
frame.sequence_id = (id >> 5) & 0x1F;
frame.sequence_total = (id >> 5) & 0x1F;
frame.sequence_total = id & 0x1F;
}
// Standard ID, this is an error.
itzandroidtab marked this conversation as resolved.
Show resolved Hide resolved
else {
Expand Down Expand Up @@ -386,12 +386,13 @@ namespace r2d2::can_bus {
template<typename Bus>
void _write_tx_registers(const _can_frame_s &frame, const uint8_t index) {
// Set sequence id and total
port<Bus>->CAN_MB[index].CAN_MID |=
port<Bus>->CAN_MB[index].CAN_MID =
((index + 1) << 26) |
((frame.mode & 0x01) << 25) |
(frame.frame_type << 10) |
((frame.sequence_id & 0x1F) << 5) |
(frame.sequence_total & 0x1F);
(frame.sequence_total & 0x1F) |
CAN_MID_MIDE;

// Set the data length on the mailbox.
port<Bus>->CAN_MB[index].CAN_MCR =
Expand Down
107 changes: 87 additions & 20 deletions code/headers/channel.hpp
Expand Up @@ -7,6 +7,7 @@
#include "can.hpp"
#include <queue.hpp>
#include <ringbuffer.hpp>
#include <cmath>
#include "base_comm.hpp"

namespace r2d2::can_bus {
Expand Down Expand Up @@ -98,6 +99,38 @@ namespace r2d2::can_bus {
// send interrupt.
inline static queue_c<detail::_can_frame_s, 32> tx_queue;

/**
* Volatile flag that is used to signify that there is space
* in the tx_queue. The tx_queue is emptied in an interrupt and the
* send_frame function will wait until there is space in the tx_queue before
* it continues execution.
*
* However; using while(tx_queue.full()) {} will cause the compiler to
itzandroidtab marked this conversation as resolved.
Show resolved Hide resolved
* optimize this to a while(true); loop. This is not the desired behaviour.
* We can't mark the tx_queue itself als volatile, since that would require marking
* all its member functions as volatile as well. So a flag that is cleared each time
* the size of tx_queue is reduced is the best option.
*/
inline volatile static bool space_in_tx_queue = true;

/**
* Place a frame into the tx_queue, accounting for
* a full transfer queue and waiting for the interrupt
* to resolve.
*
* @param frame
*/
static void safely_push_frame(const detail::_can_frame_s &frame) {
if (tx_queue.full()) {
space_in_tx_queue = false;
}

// Wait for space, space is created in the interrupt
while (!space_in_tx_queue);

tx_queue.push(frame);
}

public:
/**
* Initialize the channel mailboxes.
Expand Down Expand Up @@ -132,9 +165,7 @@ namespace r2d2::can_bus {
frame.length = 0;
frame.frame_type = type;

while (tx_queue.full()) {}

tx_queue.push(frame);
safely_push_frame(frame);

// Enabling the interrupt on the CAN mailbox with the TX id
// will cause a interrupt when the CAN controller is ready.
Expand All @@ -148,22 +179,59 @@ namespace r2d2::can_bus {
*
* @param frame
*/
template<typename T>
static void send_frame(const T &data) {
detail::_can_frame_s frame{};
static void send_frame(const frame_type &type, const uint8_t *data, const size_t length) {
/*
* If the frame is "simple" (less than or equal to 8 bytes), it will
* fit on the transport in one frame. Otherwise, a sequence
* is created.
*/
if (length <= 8) {
detail::_can_frame_s frame{};

for(size_t i = 0; i < length; i++){
frame.data.bytes[i] = data[i];
}

memcpy(
(void *) frame.data.bytes,
(const void *) &data,
sizeof(T)
);
frame.length = length;
frame.frame_type = type;

frame.length = sizeof(T);
frame.frame_type = frame_type_v<T>;
safely_push_frame(frame);
} else {
const uint_fast8_t total = length / 8;
const uint_fast8_t remainder = length % 8;
itzandroidtab marked this conversation as resolved.
Show resolved Hide resolved

while (tx_queue.full()) {}
// First, create the bulk of the frame.
for (uint_fast8_t i = 0; i < total; i++) {
detail::_can_frame_s frame{};

tx_queue.push(frame);
for(uint_fast8_t j = 0; j < 8; j++){
frame.data.bytes[j] = data[j + i];
}

frame.length = 8;
frame.frame_type = type;
frame.sequence_id = i;
frame.sequence_total = total + (remainder > 0);

safely_push_frame(frame);
}

// Handle any remaining bytes
if (remainder > 0) {
detail::_can_frame_s frame{};

for(uint_fast8_t i = 0; i < remainder; i++){
frame.data.bytes[i] = data[i + total];
}

frame.length = remainder;
frame.frame_type = type;
frame.sequence_id = total;
frame.sequence_total = total + 1;

safely_push_frame(frame);
}
}

// Enabling the interrupt on the CAN mailbox with the TX id
// will cause a interrupt when the CAN controller is ready.
Expand Down Expand Up @@ -195,6 +263,7 @@ namespace r2d2::can_bus {
// Put the data on the bus
const auto frame = tx_queue.copy_and_pop();
detail::_write_tx_registers<Bus>(frame, ids::tx);
space_in_tx_queue = true;
} else {
// Nothing left to send, disable interrupt on the tx mailbox
port<Bus>->CAN_IDR = (0x01 << ids::tx);
Expand All @@ -212,11 +281,9 @@ namespace r2d2::can_bus {
frame.type = static_cast<frame_type>(can_frame.frame_type);
frame.request = can_frame.mode == detail::_can_frame_mode::READ;

memcpy(
(void *) frame.bytes,
(const void *) can_frame.data.bytes,
8 // Has to be 8 bytes; frame.length is copied in a lower layer
);
for(uint_fast8_t i = 0; i < 8; i++){
itzandroidtab marked this conversation as resolved.
Show resolved Hide resolved
frame.bytes[i] = can_frame.data.bytes[i];
}

using regs = comm_module_register_s;

Expand Down
34 changes: 24 additions & 10 deletions code/headers/comm.hpp
Expand Up @@ -51,25 +51,34 @@ namespace r2d2 {
* @param buffer
* @param prio
*/
void send_impl(const frame_type &type, const uint8_t data[], const priority prio) override {
void send_impl(const frame_type &type, const uint8_t data[], const size_t length, const priority prio) override {
if (prio == priority::NORMAL) {
channel<priority::NORMAL>::send_frame(data);
channel<priority::NORMAL>::send_frame(type, data, length);
} else if (prio == priority::HIGH) {
channel<priority::HIGH>::send_frame(data);
channel<priority::HIGH>::send_frame(type, data, length);
} else if (prio == priority::LOW) {
channel<priority::LOW>::send_frame(data);
channel<priority::LOW>::send_frame(type, data, length);
} else {
channel<priority::DATA_STREAM>::send_frame(data);
channel<priority::DATA_STREAM>::send_frame(type, data, length);
}

// Only internally distribute when needed
if (can_bus::comm_module_register_s::count <= 1) {
return;
}

frame_s frame{};
frame.type = type;

memcpy(
(void *) frame.bytes,
(const void *) &data,
8
);
// memcpy(
itzandroidtab marked this conversation as resolved.
Show resolved Hide resolved
// (void *) frame.bytes,
// (const void *) &data,
// 8
// );

for(uint_fast8_t i = 0; i < 8; i++){
frame.bytes[i] = data[i];
}

distribute_frame_internally(frame);
}
Expand Down Expand Up @@ -116,6 +125,11 @@ namespace r2d2 {
channel<priority::DATA_STREAM>::request_frame(type);
}

// Only internally distribute when needed
if (can_bus::comm_module_register_s::count <= 1) {
return;
}

frame_s frame;
frame.type = type;
frame.request = true;
Expand Down
3 changes: 2 additions & 1 deletion code/headers/mock_bus.hpp
Expand Up @@ -17,7 +17,8 @@ namespace r2d2 {
* @param buffer
* @param prio
*/
void send_impl(const frame_type &type, const uint8_t data[], const priority prio) override {
void send_impl(const frame_type &type, const uint8_t data[], const size_t length, const priority prio) override {
// TODO: large frame support
frame_s frame{};
frame.type = type;

Expand Down
25 changes: 25 additions & 0 deletions code/headers/packet_types.hpp
Expand Up @@ -57,6 +57,7 @@ namespace r2d2 {
ACTIVITY_LED_STATE,

// Don't touch
EXTERNAL,
ALL,
COUNT
};
Expand Down Expand Up @@ -104,7 +105,31 @@ namespace r2d2 {
template<typename T>
constexpr frame_id frame_type_v = frame_type_s<T>::type;

/**
* A struct that helps to describe
* an external system address.
* Might change, depending on the external
* communication module.
*/
struct external_id_s {
// 3th and 4th octet
uint8_t octets[2];
};

/**
* This frame describes a frame meant for external
* systems. Tparam T describes the actual frame being send;
* this structs wraps the internal frame.
*
* @tparam T
*/
struct frame_external_s {
uint8_t data[256];
uint8_t length;
external_id_s id;
};

R2D2_INTERNAL_FRAME_HELPER(frame_external_s, EXTERNAL)

/** USER STRUCTS */

Expand Down
4 changes: 2 additions & 2 deletions examples/led_button/button/module.hpp
Expand Up @@ -41,10 +41,10 @@ namespace r2d2::button {
// Get button state, create frame and send
frame_button_state_s button_state;

button_state.pressed = button.read();
button_state.pressed = !button.read();

comm.send(button_state);
}
}
}
};
}
2 changes: 1 addition & 1 deletion examples/led_button/controller/module.hpp
Expand Up @@ -44,5 +44,5 @@ namespace r2d2::controller {
comm.send(led_state);
}
}
}
};
}