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

Freerb/lv #343

Draft
wants to merge 17 commits into
base: dev/can
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,11 @@ enable_language(C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)
set(CMAKE_CXX_STANDARD 20) # required for c++ concepts
set(CMAKE_CXX_STANDARD 23) # required for c++ concepts
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
set(CMAKE_CXX_EXTENSIONS ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi")

add_executable(main)

Expand Down
9 changes: 4 additions & 5 deletions firmware/mcal/cli/periph/can.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <chrono>
#include <cstring>
#include <iomanip>
#include <format>
#include <iostream>

#include "shared/comms/can/msg.hpp"
Expand All @@ -26,8 +24,9 @@ class CanBase : public shared::periph::CanBase {
std::cout << "can interface: " << iface_ << std::endl;
}

void Send(const shared::can::RawMessage& msg) {
std::cout << std::format("{} {}", iface_, msg) << std::endl;
void Send(const shared::can::RawMessage& msg) override {
std::cout << std::format("CanBase {}: Sending\n| {}", iface_, msg)
<< std::endl;
}

private:
Expand Down
4 changes: 2 additions & 2 deletions firmware/mcal/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
add_library(mcal-linux STATIC)
add_library(mcal-linux INTERFACE)

target_include_directories(mcal-linux PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../..)
target_include_directories(mcal-linux INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../..)

add_subdirectory(periph)
target_link_libraries(mcal-linux INTERFACE shared)
4 changes: 2 additions & 2 deletions firmware/mcal/linux/periph/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
target_sources(mcal-linux
PRIVATE
INTERFACE
adc.cc
can.cc
digital_input.cc
digital_output.cc
)

add_subdirectory(vcan)
target_link_libraries(mcal-linux PUBLIC vcan pthread)
target_link_libraries(mcal-linux INTERFACE vcan pthread)
2 changes: 1 addition & 1 deletion firmware/mcal/linux/periph/adc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <format>
#include <iostream>

#include "adc.h"
#include "adc.hpp"

namespace mcal::lnx::periph {

Expand Down
12 changes: 6 additions & 6 deletions firmware/mcal/linux/periph/can.cc
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
#include <linux/can.h>
#include <sys/types.h>

#include <chrono>
#include <cstring>
#include <format>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <thread>

#include "can.h"
#include "can.hpp"
#include "shared/comms/can/msg.hpp"
#include "vcan/vcan.h"
#include "vcan/vcan.hpp"

static can_frame to_can_frame(const shared::can::RawMessage& msg) {
struct can_frame frame{
Expand Down Expand Up @@ -53,8 +50,11 @@ void CanBase::StartReading() {
exit(1);
}

shared::can::RawMessage raw_msg(frame.can_id, frame.can_dlc,
shared::can::RawMessage raw_msg(frame.can_id, true, frame.can_dlc,
frame.data);
std::cout << std::format("CanBase {}: Received\n| {}",
socket_.GetIface(), raw_msg)
<< std::endl;

AddToBus(raw_msg);
}
Expand Down
2 changes: 1 addition & 1 deletion firmware/mcal/linux/periph/can.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include "mcal/linux/periph/vcan/vcan.hpp"
#include "shared/periph/can.hpp"
#include "vcan/vcan.h"
#include "vcan/vcan.hpp"

namespace mcal::lnx::periph {

Expand Down
2 changes: 1 addition & 1 deletion firmware/mcal/linux/periph/digital_input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <iostream>
#include <string>

#include "digital_input.h"
#include "digital_input.hpp"

namespace mcal::lnx::periph {

Expand Down
2 changes: 1 addition & 1 deletion firmware/mcal/linux/periph/digital_output.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <iostream>
#include <string>

#include "digital_output.h"
#include "digital_output.hpp"

namespace mcal::lnx::periph {

Expand Down
2 changes: 1 addition & 1 deletion firmware/mcal/linux/periph/vcan/vcan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <iostream>
#include <string>

#include "vcan.h"
#include "vcan.hpp"

namespace mcal::lnx::periph::vcan {

Expand Down
2 changes: 1 addition & 1 deletion firmware/mcal/stm32f767/periph/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# Empty file - implicitly adds this folder as an include directory
target_sources(mcal-stm32f767 INTERFACE can.cc)
141 changes: 141 additions & 0 deletions firmware/mcal/stm32f767/periph/can.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include "stm32f7xx_hal.h"
#ifdef HAL_CAN_MODULE_ENABLED

#include <cstdint>

#include "can.hpp"

// FIFO0 is the "high priority" queue on stm32f7. We do not use FIFO1
constexpr uint32_t kCanFifo = CAN_RX_FIFO0;
constexpr uint32_t kCanInterrupt = CAN_IT_RX_FIFO0_MSG_PENDING;

namespace { // InterruptHandler is private to this file

/// Prior to this class, we spent several hours debugging an issue where the
/// interrupt was activated but the handler was not being called, causing the
/// program to get repeatedly executed the interupt callback and stall the rest
/// of the program.
/// This class ensures that interrupts activated and handled together.
class InterruptHandler {
using CanBase = mcal::stm32f767::periph::CanBase;

public:
void RegisterCanBase(CAN_HandleTypeDef* hcan, CanBase* can_base) {
int index = HandleToIndex(hcan);
if (index == -1) return;

can_bases[index] = can_base;
HAL_CAN_ActivateNotification(hcan, kCanInterrupt);
}

void Handle(CAN_HandleTypeDef* hcan) {
int index = HandleToIndex(hcan);
if (index == -1) return;

auto can_base = can_bases[index];
if (can_base != nullptr) {
can_bases[index]->Receive();
}
}

private:
CanBase* can_bases[3] = {nullptr, nullptr, nullptr};

int HandleToIndex(CAN_HandleTypeDef* hcan) {
// CANx are not contiguous in memory, so we can't use a simple array
if (hcan->Instance == CAN1) {
return 0;
} else if (hcan->Instance == CAN2) {
return 1;
} else if (hcan->Instance == CAN3) {
return 2;
} else {
return -1;
}
}
};
} // namespace

static InterruptHandler interrupt_handler;

extern "C" {
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* hcan) {
// Overrides the "weak" callback defined by CubeMX
interrupt_handler.Handle(hcan);
}
}

namespace mcal::stm32f767::periph {

CanBase::CanBase(CAN_HandleTypeDef* hcan) : hcan_{hcan} {}

void CanBase::Setup() {
ConfigFilters();
interrupt_handler.RegisterCanBase(hcan_, this);
HAL_CAN_Start(hcan_);
}

void CanBase::Send(const shared::can::RawMessage& msg) {
uint32_t tx_mailboxes_free_level = HAL_CAN_GetTxMailboxesFreeLevel(hcan_);
if (tx_mailboxes_free_level < 1) {
dropped_tx_frames_ += 1;
return;
}

CAN_TxHeaderTypeDef stm_tx_header;
stm_tx_header.RTR = CAN_RTR_DATA; // we only support data frames currently
stm_tx_header.DLC = msg.data_length;

if (msg.is_extended_frame) {
stm_tx_header.IDE = CAN_ID_EXT;
stm_tx_header.ExtId = msg.id;
} else {
stm_tx_header.IDE = CAN_ID_STD;
stm_tx_header.StdId = msg.id;
}

HAL_CAN_AddTxMessage(hcan_, &stm_tx_header, msg.data, &tx_mailbox_addr_);
}

void CanBase::Receive() {
shared::can::RawMessage rx_msg;

CAN_RxHeaderTypeDef stm_rx_header;
HAL_CAN_GetRxMessage(hcan_, kCanFifo, &stm_rx_header, rx_msg.data);

rx_msg.is_extended_frame = stm_rx_header.IDE == CAN_ID_EXT;
rx_msg.data_length = static_cast<uint8_t>(stm_rx_header.DLC);
if (rx_msg.is_extended_frame) {
rx_msg.id = stm_rx_header.ExtId;
} else {
rx_msg.id = stm_rx_header.StdId;
}

AddToBus(rx_msg);
}

inline uint32_t CanBase::GetTimestamp() const {
return HAL_GetTick() * HAL_GetTickFreq();
}

void CanBase::ConfigFilters() {
// Currently we don't support filtering - all messages are accepted
CAN_FilterTypeDef filter_config{
.FilterIdHigh = 0x0000,
.FilterIdLow = 0x0000,
.FilterMaskIdHigh = 0x0000,
.FilterMaskIdLow = 0x0000,
.FilterFIFOAssignment = kCanFifo,
.FilterBank = 0,
.FilterMode = CAN_FILTERMODE_IDMASK,
.FilterScale = CAN_FILTERSCALE_32BIT,
.FilterActivation = CAN_FILTER_ENABLE,
.SlaveStartFilterBank = 14,
};

HAL_CAN_ConfigFilter(hcan_, &filter_config);
}

} // namespace mcal::stm32f767::periph

#endif // HAL_CAN_MODULE_ENABLED
Loading