Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but that tree was gitignored, so a clone of this repository could not build the firmware it ships. It is now committed here as ordinary files in its own folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP bridge's signature verification (--trust) used on the bench. Nothing is fetched from or pushed to the colleague's repository; this repository and its remotes carry everything. The folder's own .gitignore keeps build output, downloaded components and private key material out, as it did there; the committed file set is identical to that repository's tracked files. The ESP32-C5 is still flashed from obu-firmware/, which only takes vanetza-idf from microbu-esp32c5/, so the two stay separate folders. FLASHING.md says how to take a newer version of the colleague's tree (copy it over the folder, rebuild, test, commit).
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
set(CXX_SOURCES
|
||||
access_category.cpp
|
||||
data_rates.cpp
|
||||
g5_link_layer.cpp
|
||||
)
|
||||
add_vanetza_component(access ${CXX_SOURCES})
|
||||
target_link_libraries(access PUBLIC net)
|
||||
|
||||
add_test_subdirectory(tests)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <vanetza/access/access_category.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, AccessCategory ac)
|
||||
{
|
||||
switch (ac) {
|
||||
case AccessCategory::BK:
|
||||
os << "AC_BK";
|
||||
break;
|
||||
case AccessCategory::BE:
|
||||
os << "AC_BE";
|
||||
break;
|
||||
case AccessCategory::VI:
|
||||
os << "AC_VI";
|
||||
break;
|
||||
case AccessCategory::VO:
|
||||
os << "AC_VO";
|
||||
break;
|
||||
default:
|
||||
os << "<unknown AC>";
|
||||
break;
|
||||
};
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef ACCESS_CATEGORY_HPP_QAWSOPED
|
||||
#define ACCESS_CATEGORY_HPP_QAWSOPED
|
||||
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
/**
|
||||
* \enum AccessCategory
|
||||
* \brief AccessCategory represents packet priority at link layer
|
||||
*
|
||||
* Each enumerator's value matches the user priority UP (802.1D)
|
||||
* of the respective access category AC (802.11).
|
||||
*
|
||||
* See ETSI EN 302 663 V1.2.1 (2013-07), Table B.3
|
||||
*/
|
||||
enum class AccessCategory {
|
||||
BK = 1, //!< Background (lowest priority)
|
||||
BE = 3, //!< Best effort
|
||||
VI = 5, //!< Video
|
||||
VO = 7 //!< Voice (highest priority)
|
||||
}; /**< \enum */
|
||||
|
||||
std::ostream& operator<<(std::ostream&, AccessCategory);
|
||||
|
||||
constexpr std::uint8_t user_priority(AccessCategory ac)
|
||||
{
|
||||
return static_cast<std::uint8_t>(ac) & 0x7;
|
||||
}
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* ACCESS_CATEGORY_HPP_QAWSOPED */
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "data_rates.hpp"
|
||||
#include <cassert>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
std::size_t DataRateG5::data_length(std::size_t psdu) const
|
||||
{
|
||||
static const unsigned service_bits = 16;
|
||||
static const unsigned tail_bits = 6;
|
||||
|
||||
const unsigned body = service_bits + tail_bits + psdu * 8;
|
||||
unsigned padding = body % m_coded_bits_per_symbol;
|
||||
if (padding > 0) {
|
||||
padding = m_coded_bits_per_symbol - padding;
|
||||
}
|
||||
|
||||
assert((body + padding) % 8 == 0);
|
||||
return (body + padding) / 8;
|
||||
}
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef DATA_RATES_802DOT11P_HPP_SL3RZPZO
|
||||
#define DATA_RATES_802DOT11P_HPP_SL3RZPZO
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
class DataRateG5
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create data rate for ITS-G5 band
|
||||
* \param kbps kilo-bits per second transfer rate
|
||||
* \param cbits number of coded bits per symbol
|
||||
*/
|
||||
constexpr DataRateG5(unsigned kbps, unsigned cbits) :
|
||||
m_bytes_per_second(kbps * 1000 / 8),
|
||||
m_coded_bits_per_symbol(cbits) {}
|
||||
|
||||
/**
|
||||
* Get tranfer rate as number of bytes per second
|
||||
* \return transfer rate
|
||||
*/
|
||||
unsigned bytes_per_second() const { return m_bytes_per_second; }
|
||||
|
||||
/**
|
||||
* Calculate length of PHY data length
|
||||
* \param psdu size of PSDU, i.e. MPDU (MAC header + payload)
|
||||
* \return length in bytes
|
||||
*/
|
||||
std::size_t data_length(std::size_t psdu) const;
|
||||
|
||||
private:
|
||||
unsigned m_bytes_per_second;
|
||||
unsigned m_coded_bits_per_symbol;
|
||||
};
|
||||
|
||||
static const DataRateG5 G5_3Mbps { 3000, 48 };
|
||||
static const DataRateG5 G5_4dot5Mbps { 4500, 48 };
|
||||
static const DataRateG5 G5_6Mbps { 6000, 96 };
|
||||
static const DataRateG5 G5_9Mbps { 9000, 96 };
|
||||
static const DataRateG5 G5_12Mbps { 12000, 192 };
|
||||
static const DataRateG5 G5_18bps { 18000, 192 };
|
||||
static const DataRateG5 G5_24Mbps { 24000, 288 };
|
||||
static const DataRateG5 G5_27Mbps { 27000, 288 };
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* DATA_RATES_802DOT11P_HPP_SL3RZPZO */
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef DATA_REQUEST_HPP_3OGGPFWF
|
||||
#define DATA_REQUEST_HPP_3OGGPFWF
|
||||
|
||||
#include <vanetza/access/access_category.hpp>
|
||||
#include <vanetza/common/byte_order.hpp>
|
||||
#include <vanetza/net/mac_address.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
struct DataRequest
|
||||
{
|
||||
DataRequest() : access_category(AccessCategory::BK) {}
|
||||
|
||||
uint16be_t ether_type;
|
||||
MacAddress source_addr;
|
||||
MacAddress destination_addr;
|
||||
AccessCategory access_category;
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* DATA_REQUEST_HPP_3OGGPFWF */
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef ETHERTYPE_HPP_ED3SIJFX
|
||||
#define ETHERTYPE_HPP_ED3SIJFX
|
||||
|
||||
#include <vanetza/common/byte_order.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
using EtherType = uint16be_t;
|
||||
|
||||
namespace ethertype
|
||||
{
|
||||
|
||||
static const EtherType GeoNetworking = host_cast<uint16_t>(0x8947);
|
||||
static const EtherType WSMP = host_cast<uint16_t>(0x88DC);
|
||||
|
||||
} // namespace ethertype
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* ETHERTYPE_HPP_ED3SIJFX */
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
#include <vanetza/access/g5_link_layer.hpp>
|
||||
#include <vanetza/access/ethertype.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
static const ieee802::LlcSnapHeader default_llc_header { ethertype::GeoNetworking };
|
||||
|
||||
G5LinkLayer::G5LinkLayer() :
|
||||
llc_snap_header(default_llc_header)
|
||||
{
|
||||
}
|
||||
|
||||
void serialize(OutputArchive& ar, const G5LinkLayer& g5)
|
||||
{
|
||||
serialize(ar, g5.mac_header);
|
||||
serialize(ar, g5.llc_snap_header);
|
||||
}
|
||||
|
||||
void deserialize(InputArchive& ar, G5LinkLayer& g5)
|
||||
{
|
||||
deserialize(ar, g5.mac_header);
|
||||
deserialize(ar, g5.llc_snap_header);
|
||||
}
|
||||
|
||||
bool check_fixed_fields(const G5LinkLayer& link_layer)
|
||||
{
|
||||
static const auto default_frame_control = ieee802::dot11::FrameControl::qos_data_frame();
|
||||
static const ieee802::dot11::QosControl default_qos_control;
|
||||
|
||||
// all frame control flags are fixed for now
|
||||
static const std::uint16_t frame_control_fixed = 0xFFFF;
|
||||
|
||||
// EOSP + A-MSDU + TXOP limit fixed, TID (LSB part = UP) and Ack policy are variable
|
||||
static const std::uint16_t qos_control_fixed = 0xFF98;
|
||||
|
||||
const ieee802::dot11::QosDataHeader& mac = link_layer.mac_header;
|
||||
const bool frame_control_ok =
|
||||
(mac.frame_control.raw.get() & frame_control_fixed) == (default_frame_control.raw.get() & frame_control_fixed);
|
||||
const bool qos_control_ok =
|
||||
(mac.qos_control.raw.get() & qos_control_fixed) == (default_qos_control.raw.get() & qos_control_fixed);
|
||||
return frame_control_ok && qos_control_ok &&
|
||||
mac.sequence_control.fragment_number() == 0 &&
|
||||
mac.bssid == ieee802::dot11::bssid_wildcard &&
|
||||
link_layer.llc_snap_header == default_llc_header;
|
||||
}
|
||||
|
||||
namespace ieee802
|
||||
{
|
||||
namespace dot11
|
||||
{
|
||||
|
||||
// Operation outside of a BSS, must be set to wildcard (all bits 1)
|
||||
const MacAddress bssid_wildcard = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
void QosControl::user_priority(AccessCategory access_category)
|
||||
{
|
||||
std::uint16_t tmp = raw.get();
|
||||
tmp &= ~0x000F; // clear all TID bits
|
||||
tmp |= static_cast<std::uint16_t>(access_category) & 0x07;
|
||||
raw = static_cast<uint16be_t>(tmp);
|
||||
}
|
||||
|
||||
FrameControl FrameControl::qos_data_frame()
|
||||
{
|
||||
FrameControl frame_control;
|
||||
frame_control.raw = host_cast<std::uint16_t>(0x8800);
|
||||
return frame_control;
|
||||
}
|
||||
|
||||
void serialize(OutputArchive& ar, const QosDataHeader& mac)
|
||||
{
|
||||
serialize(ar, mac.frame_control.raw);
|
||||
serialize(ar, mac.duration_or_id);
|
||||
serialize(ar, mac.destination);
|
||||
serialize(ar, mac.source);
|
||||
serialize(ar, mac.bssid);
|
||||
serialize(ar, mac.sequence_control.raw);
|
||||
serialize(ar, mac.qos_control.raw);
|
||||
}
|
||||
|
||||
void deserialize(InputArchive& ar, QosDataHeader& mac)
|
||||
{
|
||||
deserialize(ar, mac.frame_control.raw);
|
||||
deserialize(ar, mac.duration_or_id);
|
||||
deserialize(ar, mac.destination);
|
||||
deserialize(ar, mac.source);
|
||||
deserialize(ar, mac.bssid);
|
||||
deserialize(ar, mac.sequence_control.raw);
|
||||
deserialize(ar, mac.qos_control.raw);
|
||||
}
|
||||
|
||||
} // namespace dot11
|
||||
|
||||
void serialize(OutputArchive& ar, const LlcSnapHeader& snap)
|
||||
{
|
||||
serialize(ar, snap.dsap);
|
||||
serialize(ar, snap.ssap);
|
||||
serialize(ar, snap.control);
|
||||
for (std::uint8_t byte : snap.oui) {
|
||||
ar << byte;
|
||||
}
|
||||
serialize(ar, snap.protocol_id);
|
||||
}
|
||||
|
||||
void deserialize(InputArchive& ar, LlcSnapHeader& snap)
|
||||
{
|
||||
deserialize(ar, snap.dsap);
|
||||
deserialize(ar, snap.ssap);
|
||||
deserialize(ar, snap.control);
|
||||
for (std::uint8_t& byte : snap.oui) {
|
||||
ar >> byte;
|
||||
}
|
||||
deserialize(ar, snap.protocol_id);
|
||||
}
|
||||
|
||||
bool operator==(const LlcSnapHeader& a, const LlcSnapHeader& b)
|
||||
{
|
||||
return a.dsap == b.dsap && a.ssap == b.ssap && a.control == b.control &&
|
||||
a.oui == b.oui && a.protocol_id == b.protocol_id;
|
||||
}
|
||||
|
||||
bool operator!=(const LlcSnapHeader& a, const LlcSnapHeader& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
} // namespace ieee802
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
@@ -0,0 +1,164 @@
|
||||
#ifndef G5_LINK_LAYER_HPP_CESAPUOW
|
||||
#define G5_LINK_LAYER_HPP_CESAPUOW
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <vanetza/access/access_category.hpp>
|
||||
#include <vanetza/common/bit_number.hpp>
|
||||
#include <vanetza/common/byte_order.hpp>
|
||||
#include <vanetza/common/serialization.hpp>
|
||||
#include <vanetza/net/mac_address.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
namespace ieee802
|
||||
{
|
||||
namespace dot11
|
||||
{
|
||||
|
||||
/**
|
||||
* \brief QoS Control field in IEEE 802.11 MAC header.
|
||||
*/
|
||||
struct QosControl
|
||||
{
|
||||
vanetza::uint16be_t raw { 0 };
|
||||
|
||||
/**
|
||||
* Set user priority by access category
|
||||
* \param ac map this AccessCategory to user priority
|
||||
*/
|
||||
void user_priority(AccessCategory ac);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Frame Control field in IEEE 802.11 MAC header
|
||||
*/
|
||||
struct FrameControl
|
||||
{
|
||||
vanetza::uint16be_t raw { 0 };
|
||||
|
||||
using Protocol = BitNumber<std::uint16_t, 2>; /**< represents protocol version */
|
||||
using Type = BitNumber<std::uint16_t, 2>;
|
||||
using SubType = BitNumber<std::uint16_t, 4>;
|
||||
|
||||
Protocol protocol() const { return Protocol(raw.get()); }
|
||||
Type type() const { return Type(raw.get() >> 2); }
|
||||
SubType sub_type() const { return SubType(raw.get() >> 4); }
|
||||
bool to_ds() const { return raw.get() & 0x0100; }
|
||||
bool from_ds() const { return raw.get() & 0x0200; }
|
||||
bool more_fragments() const { return raw.get() & 0x0400; }
|
||||
bool retry() const { return raw.get() & 0x0800; }
|
||||
|
||||
/**
|
||||
* Create frame control for QoS data frame without any flags
|
||||
* \return FrameControl field for QoS data frame
|
||||
**/
|
||||
static FrameControl qos_data_frame();
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Sequence Control field in IEEE 802.11 MAC header
|
||||
*/
|
||||
struct SequenceControl
|
||||
{
|
||||
vanetza::uint16be_t raw { 0 };
|
||||
|
||||
using SequenceNumber = BitNumber<std::uint16_t, 12>;
|
||||
using FragmentNumber = BitNumber<std::uint16_t, 4>;
|
||||
|
||||
SequenceNumber sequence_number() const
|
||||
{
|
||||
return SequenceNumber(raw.get() >> 4);
|
||||
}
|
||||
|
||||
FragmentNumber fragment_number() const
|
||||
{
|
||||
return FragmentNumber(raw.get());
|
||||
}
|
||||
};
|
||||
|
||||
/** MAC address representing the BSSID wildcard (all bits set) */
|
||||
extern const MacAddress bssid_wildcard;
|
||||
|
||||
/**
|
||||
* \brief MAC header of QoS data frames
|
||||
*/
|
||||
struct QosDataHeader
|
||||
{
|
||||
FrameControl frame_control = FrameControl::qos_data_frame();
|
||||
uint16be_t duration_or_id;
|
||||
MacAddress destination;
|
||||
MacAddress source;
|
||||
MacAddress bssid = bssid_wildcard;
|
||||
SequenceControl sequence_control;
|
||||
QosControl qos_control;
|
||||
|
||||
/** length of serialized QoSDataHeader in bytes */
|
||||
static constexpr std::size_t length_bytes = 26;
|
||||
};
|
||||
|
||||
/** length of frame check sequence in bytes */
|
||||
static constexpr std::size_t fcs_length_bytes = 4;
|
||||
|
||||
void serialize(OutputArchive&, const QosDataHeader&);
|
||||
void deserialize(InputArchive&, QosDataHeader&);
|
||||
|
||||
} // namespace dot11
|
||||
|
||||
/**
|
||||
* \brief Logical Link Control header with SNAP extension
|
||||
*/
|
||||
struct LlcSnapHeader
|
||||
{
|
||||
std::uint8_t dsap = 0xAA;
|
||||
std::uint8_t ssap = 0xAA;
|
||||
std::uint8_t control = 0x03;
|
||||
std::array<std::uint8_t, 3> oui = {{ 0x00, 0x00, 0x00 }};
|
||||
uint16be_t protocol_id;
|
||||
|
||||
LlcSnapHeader(uint16be_t protocol_id) : protocol_id(protocol_id) {}
|
||||
|
||||
static constexpr std::size_t length_bytes = 8;
|
||||
};
|
||||
|
||||
bool operator==(const LlcSnapHeader&, const LlcSnapHeader&);
|
||||
bool operator!=(const LlcSnapHeader&, const LlcSnapHeader&);
|
||||
|
||||
void serialize(OutputArchive&, const LlcSnapHeader&);
|
||||
void deserialize(InputArchive&, LlcSnapHeader&);
|
||||
|
||||
} // namespace ieee802
|
||||
|
||||
/**
|
||||
* \brief Link layer header used by ITS-G5 stations
|
||||
*/
|
||||
struct G5LinkLayer
|
||||
{
|
||||
ieee802::dot11::QosDataHeader mac_header;
|
||||
ieee802::LlcSnapHeader llc_snap_header;
|
||||
|
||||
G5LinkLayer();
|
||||
|
||||
static constexpr std::size_t length_bytes =
|
||||
ieee802::dot11::QosDataHeader::length_bytes +
|
||||
ieee802::LlcSnapHeader::length_bytes;
|
||||
};
|
||||
|
||||
void serialize(OutputArchive&, const G5LinkLayer&);
|
||||
void deserialize(InputArchive&, G5LinkLayer&);
|
||||
|
||||
/**
|
||||
* \brief Check whether some link layer header fields contain their expected values.
|
||||
* For most explicitly initialized link layer header fields, their (default) value is expected in received frames.
|
||||
*
|
||||
* \param link_layer G5LinkLayer to check
|
||||
* \return whether all fields are set as expected
|
||||
*/
|
||||
bool check_fixed_fields(const G5LinkLayer& link_layer);
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* G5_LINK_LAYER_HPP_CESAPUOW */
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef INTERFACE_HPP_EUPJ90MD
|
||||
#define INTERFACE_HPP_EUPJ90MD
|
||||
|
||||
#include <vanetza/net/chunk_packet.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
struct DataRequest;
|
||||
|
||||
class Interface
|
||||
{
|
||||
public:
|
||||
virtual void request(const DataRequest&, std::unique_ptr<ChunkPacket>) = 0;
|
||||
virtual ~Interface() {}
|
||||
};
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* INTERFACE_HPP_EUPJ90MD */
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include <vanetza/access/access_category.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace access
|
||||
{
|
||||
|
||||
/**
|
||||
* \brief map access category to PPPP for C-V2X
|
||||
*
|
||||
* Mapping is according to EN 303 613 V1.1.1 Table B.7
|
||||
*
|
||||
* \param ac access category from 802.11
|
||||
* \return matching PPPP value
|
||||
*/
|
||||
constexpr std::uint8_t pppp_from_ac(AccessCategory ac)
|
||||
{
|
||||
switch (ac) {
|
||||
case AccessCategory::VO:
|
||||
return 2;
|
||||
case AccessCategory::VI:
|
||||
return 4;
|
||||
case AccessCategory::BE:
|
||||
return 5;
|
||||
case AccessCategory::BK:
|
||||
default:
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace access
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
include(UseGTest)
|
||||
configure_gtest_directory(LINK_LIBRARIES access)
|
||||
|
||||
add_gtest(DataRates data_rates.cpp)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/access/data_rates.hpp>
|
||||
|
||||
using namespace vanetza::access;
|
||||
|
||||
TEST(DataRates, bytes_per_second)
|
||||
{
|
||||
EXPECT_EQ(G5_3Mbps.bytes_per_second(), 3 * 1000 * 1000 / 8);
|
||||
EXPECT_EQ(G5_6Mbps.bytes_per_second(), 6 * 1000 * 1000 / 8);
|
||||
EXPECT_EQ(G5_12Mbps.bytes_per_second(), 12 * 1000 * 1000 / 8);
|
||||
}
|
||||
|
||||
TEST(DataRates, data_length)
|
||||
{
|
||||
const std::size_t psdu_bytes = 385;
|
||||
const std::size_t data_bytes = G5_6Mbps.data_length(psdu_bytes);
|
||||
EXPECT_GE(data_bytes, psdu_bytes);
|
||||
EXPECT_LT(data_bytes, psdu_bytes + 12);
|
||||
}
|
||||
Reference in New Issue
Block a user