Files
MicrOBU/obu-firmware/main/link_protocol.cpp
T

187 lines
8.7 KiB
C++
Raw Normal View History

#include "link_protocol.hpp"
namespace microbu::link {
bool encode(const Message& message, Bytes& out) {
if (header_size + message.body.size() > maximum_message) return false;
out.clear();
out.reserve(header_size + message.body.size());
out.push_back(static_cast<std::uint8_t>(message.header.opcode));
out.push_back(message.header.flags);
out.push_back(message.header.sequence & 0xFF);
out.push_back(message.header.sequence >> 8);
out.insert(out.end(), message.body.begin(), message.body.end());
return true;
}
bool decode(const Bytes& octets, Message& out) {
if (octets.size() < header_size || octets.size() > maximum_message) return false;
out.header.opcode = static_cast<Opcode>(octets[0]);
out.header.flags = octets[1];
out.header.sequence = octets[2] | (octets[3] << 8);
out.body.assign(octets.begin() + header_size, octets.end());
return true;
}
namespace {
void put_area(Writer& w, const DestinationArea& a) {
w.u8(a.shape); w.i32(a.latitude); w.i32(a.longitude); w.u16(a.distance_a); w.u16(a.distance_b); w.u16(a.angle);
}
DestinationArea get_area(Reader& r) {
DestinationArea a;
a.shape = r.u8(); a.latitude = r.i32(); a.longitude = r.i32(); a.distance_a = r.u16(); a.distance_b = r.u16(); a.angle = r.u16();
return a;
}
}
// STATION_CONFIGURE
Bytes encode(const StationConfigure& c) {
Writer w;
w.u8(c.station_type); w.u8(c.security); w.u8(c.address_configuration); w.bytes(c.mid, 6); w.u8(c.beaconing);
w.u16(c.channel_number); w.u8(c.transmit_power_dbm); w.u8(c.radio); w.u8(c.default_traffic_class); w.u8(c.default_lifetime);
return w.out;
}
bool decode(const Bytes& body, StationConfigure& c) {
Reader r(body);
c.station_type = r.u8(); c.security = r.u8(); c.address_configuration = r.u8(); r.bytes(c.mid, 6); c.beaconing = r.u8();
c.channel_number = r.u16(); c.transmit_power_dbm = r.u8(); c.radio = r.u8(); c.default_traffic_class = r.u8(); c.default_lifetime = r.u8();
return r.done() && c.security <= 1 && c.address_configuration <= 1 && c.beaconing <= 1 && c.radio <= 2;
}
// POTI_UPDATE
Bytes encode(const PotiUpdate& p) {
Writer w;
w.u64(p.timestamp_ms); w.i32(p.latitude); w.i32(p.longitude); w.u16(p.semi_major_cm); w.u16(p.semi_minor_cm);
w.u16(p.orientation_deci_degree); w.u8(p.flags); w.i32(p.altitude_cm); w.u16(p.speed_cm_s); w.u16(p.heading_deci_degree);
return w.out;
}
bool decode(const Bytes& body, PotiUpdate& p) {
Reader r(body);
p.timestamp_ms = r.u64(); p.latitude = r.i32(); p.longitude = r.i32(); p.semi_major_cm = r.u16(); p.semi_minor_cm = r.u16();
p.orientation_deci_degree = r.u16(); p.flags = r.u8(); p.altitude_cm = r.i32(); p.speed_cm_s = r.u16(); p.heading_deci_degree = r.u16();
return r.done();
}
// BTP_DATA_REQUEST
Bytes encode(const BtpDataRequest& q) {
Writer w;
w.u8(q.btp_type); w.u16(q.destination_port); w.u16(q.destination_port_info); w.u8(q.gn_packet_transport_type);
w.u8(q.gn_communication_profile); w.u8(q.gn_security_profile); w.u8(q.gn_traffic_class); w.u8(q.gn_maximum_packet_lifetime);
w.u8(q.gn_maximum_hop_limit); w.u16(q.gn_repetition_interval_ms); w.u16(q.gn_repetition_maximum_ms); w.u32(q.its_aid);
w.u8(static_cast<std::uint8_t>(q.permissions.size())); w.bytes(q.permissions);
w.u8(static_cast<std::uint8_t>(q.context.size())); w.bytes(q.context);
if (q.gn_packet_transport_type == 3) put_area(w, q.area.value_or(DestinationArea {}));
w.u16(static_cast<std::uint16_t>(q.fl_sdu.size())); w.bytes(q.fl_sdu);
return w.out;
}
bool decode(const Bytes& body, BtpDataRequest& q) {
Reader r(body);
q.btp_type = r.u8(); q.destination_port = r.u16(); q.destination_port_info = r.u16(); q.gn_packet_transport_type = r.u8();
q.gn_communication_profile = r.u8(); q.gn_security_profile = r.u8(); q.gn_traffic_class = r.u8(); q.gn_maximum_packet_lifetime = r.u8();
q.gn_maximum_hop_limit = r.u8(); q.gn_repetition_interval_ms = r.u16(); q.gn_repetition_maximum_ms = r.u16(); q.its_aid = r.u32();
q.permissions = r.bytes(r.u8());
q.context = r.bytes(r.u8());
q.area.reset();
if (q.gn_packet_transport_type == 3) q.area = get_area(r);
q.fl_sdu = r.bytes(r.u16());
return r.done() && q.btp_type <= 1 && q.permissions.size() <= 31;
}
// BTP_DATA_INDICATION
Bytes encode(const BtpDataIndication& i) {
Writer w;
w.u8(i.btp_type); w.u16(i.destination_port); w.u16(i.destination_port_info); w.u8(i.gn_packet_transport_type);
w.u8(i.gn_traffic_class); w.u8(i.gn_remaining_packet_lifetime); w.u8(i.gn_remaining_hop_limit);
w.bytes(i.source_gn_address, 8); w.u32(i.source_timestamp); w.i32(i.source_latitude); w.i32(i.source_longitude);
w.u8(i.security_report); w.u32(i.its_aid);
w.u8(static_cast<std::uint8_t>(i.permissions.size())); w.bytes(i.permissions);
w.u8(i.certificate_present ? 1 : 0); w.bytes(i.certificate_id, 8);
w.u8(i.area ? 1 : 0);
if (i.area) put_area(w, *i.area);
w.u16(static_cast<std::uint16_t>(i.received_fl_sdu.size())); w.bytes(i.received_fl_sdu);
return w.out;
}
bool decode(const Bytes& body, BtpDataIndication& i) {
Reader r(body);
i.btp_type = r.u8(); i.destination_port = r.u16(); i.destination_port_info = r.u16(); i.gn_packet_transport_type = r.u8();
i.gn_traffic_class = r.u8(); i.gn_remaining_packet_lifetime = r.u8(); i.gn_remaining_hop_limit = r.u8();
r.bytes(i.source_gn_address, 8); i.source_timestamp = r.u32(); i.source_latitude = r.i32(); i.source_longitude = r.i32();
i.security_report = r.u8(); i.its_aid = r.u32();
i.permissions = r.bytes(r.u8());
i.certificate_present = r.u8() != 0; r.bytes(i.certificate_id, 8);
i.area.reset();
if (r.u8()) i.area = get_area(r);
i.received_fl_sdu = r.bytes(r.u16());
return r.done();
}
// CREDENTIALS_PROVISION
Bytes encode(const CredentialsProvision& c) {
Writer w;
w.u16(c.total_length); w.u16(c.offset); w.u8(static_cast<std::uint8_t>(c.segment.size())); w.bytes(c.segment);
return w.out;
}
bool decode(const Bytes& body, CredentialsProvision& c) {
Reader r(body);
c.total_length = r.u16(); c.offset = r.u16(); c.segment = r.bytes(r.u8());
return r.done() && !c.segment.empty() && c.offset + c.segment.size() <= c.total_length;
}
// SF_IDCHANGE_EVENT
Bytes encode(const IdChangeEvent& e) {
Writer w;
w.u64(e.subscription); w.u8(e.command); w.bytes(e.id, 8);
w.u8(static_cast<std::uint8_t>(e.subscriber_data.size())); w.bytes(e.subscriber_data);
return w.out;
}
bool decode(const Bytes& body, IdChangeEvent& e) {
Reader r(body);
e.subscription = r.u64(); e.command = r.u8(); r.bytes(e.id, 8); e.subscriber_data = r.bytes(r.u8());
return r.done() && e.command <= 3;
}
Bytes encode(const IdChangeEventResponse& e) { Writer w; w.u64(e.subscription); w.u8(e.return_code); return w.out; }
bool decode(const Bytes& body, IdChangeEventResponse& e) {
Reader r(body);
e.subscription = r.u64(); e.return_code = r.u8();
return r.done() && e.return_code <= 1;
}
// STATUS
Bytes encode(const Status& s) {
Writer w;
w.u32(s.uptime_ms); w.u8(s.configured); w.bytes(s.gn_address, 8); w.bytes(s.identifier, 8); w.u8(s.change_pending); w.u8(s.tickets);
w.u32(s.signed_messages); w.u32(s.refused_no_ticket); w.u32(s.refused_change_pending); w.u32(s.refused_permission);
w.u32(s.sign_failed); w.u32(s.verified); w.u32(s.rejected);
w.u32(s.requests_accepted); w.u32(s.requests_refused); w.u32(s.indications);
w.u32(s.radio_submitted); w.u32(s.radio_failed); w.u32(s.radio_received); w.u32(s.radio_dropped);
w.u32(s.link_rx_frames); w.u32(s.link_crc_errors); w.u32(s.link_malformed); w.u32(s.poti_updates);
w.u64(s.its_time_ms);
return w.out;
}
bool decode(const Bytes& body, Status& s) {
Reader r(body);
s.uptime_ms = r.u32(); s.configured = r.u8(); r.bytes(s.gn_address, 8); r.bytes(s.identifier, 8); s.change_pending = r.u8(); s.tickets = r.u8();
s.signed_messages = r.u32(); s.refused_no_ticket = r.u32(); s.refused_change_pending = r.u32(); s.refused_permission = r.u32();
s.sign_failed = r.u32(); s.verified = r.u32(); s.rejected = r.u32();
s.requests_accepted = r.u32(); s.requests_refused = r.u32(); s.indications = r.u32();
s.radio_submitted = r.u32(); s.radio_failed = r.u32(); s.radio_received = r.u32(); s.radio_dropped = r.u32();
s.link_rx_frames = r.u32(); s.link_crc_errors = r.u32(); s.link_malformed = r.u32(); s.poti_updates = r.u32();
s.its_time_ms = r.u64();
return r.done();
}
// RESULT
Bytes encode(const Result& res) {
Writer w;
w.u8(static_cast<std::uint8_t>(res.code)); w.u8(static_cast<std::uint8_t>(res.detail.size())); w.bytes(res.detail);
return w.out;
}
bool decode(const Bytes& body, Result& res) {
Reader r(body);
res.code = static_cast<Code>(r.u8()); res.detail = r.bytes(r.u8());
return r.done();
}
} // namespace microbu::link