8#include "core/device/cobs_device.h"
9#include "core/device/vdb/protocol.h"
15template <
typename... Fields>
16class Device :
public COBSSerialDevice {
18 static constexpr int32_t NO_ACTIVITY_DELAY = 2;
19 static constexpr std::size_t MAX_OUT_QUEUE_SIZE = 50;
20 static constexpr std::size_t MAX_IN_QUEUE_SIZE = 50;
22 enum SEND_PACKET_STATE { SUCCESS, NONE_QUEUED, ERROR };
29 explicit Device(int32_t port, int32_t baud_rate, VDP::Channel<Fields>&... channels)
30 : COBSSerialDevice(port, baud_rate), channels_(channels...) {
31 static_assert(
sizeof...(channels) <= VDP::MAX_CHANNELS,
32 "There can be no more than 256 Channels sent to a VDB Device");
33 serial_task = vex::task(Device::serial_thread, (
void*)
this, vex::thread::threadPriorityHigh);
40 bool add_to_queue(
const VDP::Packet& packet) {
42 printf(
"VDP WARNING: Empty Packets are not allowed\n");
45 outbound_mutex.lock();
46 if (outbound_packets.size() >= MAX_OUT_QUEUE_SIZE) {
47 outbound_mutex.unlock();
50 outbound_packets.push_back(packet);
51 outbound_mutex.unlock();
56 SEND_PACKET_STATE write_packet_from_queue() {
58 VDP::Packet outbound_packet = {};
60 outbound_mutex.lock();
62 if (outbound_packets.size() > 0) {
64 outbound_packet = std::move(outbound_packets.front());
65 outbound_packets.pop_front();
68 outbound_mutex.unlock();
69 if (outbound_packet.size() == 0) {
73 int sent = send_cobs_packet_blocking(outbound_packet.data(), outbound_packet.size());
78 printf(
"Failed to send packet (%d):\n", sent);
79 hexdump(outbound_packet.data(), outbound_packet.size());
85 static int serial_thread(
void* vself) {
87 Device& self = *(Device*)vself;
91 bool did_something =
false;
94 SEND_PACKET_STATE send_state = self.write_packet_from_queue();
95 if (send_state != NONE_QUEUED) {
99 if (self.poll_incoming_data_once()) {
101 decoded = self.get_last_decoded_packet();
102 self.apply_packet(decoded);
103 did_something =
true;
105 if (!did_something) {
106 vexDelay(NO_ACTIVITY_DELAY);
116 void send_channel(VDP::ChannelID
id) {
118 [&](
auto&... channel) {
121 if (
id == channel.get_id()) {
123 this->add_to_queue(channel.serialize(VDP::PacketType::Data));
125 this->add_to_queue(channel.serialize(VDP::PacketType::Schema));
138 void apply_packet(VDP::Packet in) {
139 const VDP::PacketValidity status = VDP::validate_packet(in);
142 if (status == VDP::PacketValidity::BadChecksum) {
143 VDPWarnf(
"Controller: Bad packet checksum. Skipping");
145 }
else if (status == VDP::PacketValidity::TooSmall) {
146 VDPWarnf(
"Controller: Packet too small to be valid (%d bytes). Skipping", (
int)in.size());
148 }
else if (status != VDP::PacketValidity::Ok) {
149 VDPWarnf(
"Controller: Unknown validity of packet (BAD). Skipping");
154 VDP::PacketHeader header = VDP::decode_header_byte(in[0]);
155 if (header.func == VDP::PacketFunction::Send) {
156 if (header.type == VDP::PacketType::Data) {
158 VDP::ChannelID id_to_update = in[1];
160 [&](
auto&... channel) {
163 if (id_to_update == channel.get_id()) {
164 channel.apply_update(VDP::PacketSpan(in).subspan(2));
171 VDP::Packet data_ack;
173 VDP::make_header_byte({VDP::PacketType::Data, VDP::PacketFunction::Acknowledge}));
174 data_ack.push_back(id_to_update);
175 VDP::Packet checksum = VDP::checksum_pac(data_ack);
176 data_ack.insert(data_ack.end(), checksum.begin(), checksum.end());
177 add_to_queue(data_ack);
179 }
else if (header.type == VDP::PacketType::Schema) {
180 VDP::ChannelID acked_id = in[1];
182 [&](
auto&... channel) {
185 if (acked_id == channel.get_id()) {
186 channel.acked =
false;
193 }
else if (header.func == VDP::PacketFunction::Acknowledge) {
195 if (header.type == VDP::PacketType::Schema) {
196 VDP::ChannelID acked_id = in[1];
198 [&](
auto&... channel) {
201 if (acked_id == channel.get_id()) {
202 channel.acked =
true;
217 std::deque<VDP::Packet> outbound_packets{};
218 vex::mutex outbound_mutex;
219 std::tuple<VDP::Channel<Fields>...> channels_;
221 bool waiting_to_receive =
false;
226 std::deque<WirePacket> inbound_packets;
232 WirePacket inbound_buffer;
235 vex::task serial_task;
237 std::function<void(
const VDP::Packet& packet)> callback;
239template <
typename... Fields>
240Device(int32_t, int32_t, VDP::Channel<Fields>...) -> Device<Fields...>;