File twai_receiver.h¶
File List > espos_n2k > include > espos_n2k > twai_receiver.h
Go to the documentation of this file
/* SPDX-FileCopyrightText: 2026 Dirk Wahrheit */
/* SPDX-License-Identifier: Apache-2.0 */
#ifndef COCKPIT_N2K_TWAI_RECEIVER_H_
#define COCKPIT_N2K_TWAI_RECEIVER_H_
#include <atomic>
#include <cstdint>
#include "driver/gpio.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#include <functional>
#include "espos_n2k/can_frame.h"
namespace espos_n2k {
struct TwaiReceiverConfig {
gpio_num_t tx_pin = GPIO_NUM_NC;
gpio_num_t rx_pin = GPIO_NUM_NC;
uint32_t bitrate = 250000; // NMEA 2000 standard
size_t rx_queue_depth = CONFIG_ESPOS_N2K_RX_QUEUE_DEPTH;
};
class TwaiReceiver {
public:
using FrameFn = std::function<void(const CanMessage&)>;
explicit TwaiReceiver(const TwaiReceiverConfig& config = {});
~TwaiReceiver();
void start();
void stop();
void set_on_frame(FrameFn fn) { on_frame_ = std::move(fn); }
bool ever_received() const {
return last_rx_us_.load(std::memory_order_relaxed) != 0;
}
int64_t seconds_since_last_rx() const {
int64_t last = last_rx_us_.load(std::memory_order_relaxed);
if (last == 0) return INT64_MAX;
return (esp_timer_get_time() - last) / 1000000;
}
uint32_t bus_off_count() const;
bool bus_running() const;
uint32_t frames_received() const;
uint32_t frames_dropped() const;
uint32_t error_count() const;
uint32_t last_error_flags() const;
private:
static void sink(void* ctx, const CanMessage& msg);
TwaiReceiverConfig config_;
FrameFn on_frame_;
std::atomic<bool> running_{false};
// Microseconds-since-boot of last RX frame; 0 = nothing received yet.
std::atomic<int64_t> last_rx_us_{0};
};
} // namespace espos_n2k
#endif // COCKPIT_N2K_TWAI_RECEIVER_H_