Add sorted_list, timer_queue, and DHCP discover with inline options
This commit is contained in:
@@ -11,6 +11,7 @@ pico_sdk_init()
|
|||||||
|
|
||||||
add_executable(picomap
|
add_executable(picomap
|
||||||
main.cpp
|
main.cpp
|
||||||
|
dhcp.cpp
|
||||||
net.cpp
|
net.cpp
|
||||||
tusb_config.cpp
|
tusb_config.cpp
|
||||||
w6300/w6300.cpp
|
w6300/w6300.cpp
|
||||||
|
|||||||
54
dhcp.cpp
Normal file
54
dhcp.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#include "dhcp.h"
|
||||||
|
#include <span>
|
||||||
|
#include "w6300.h"
|
||||||
|
|
||||||
|
namespace dhcp_opt {
|
||||||
|
constexpr uint8_t message_type = 53;
|
||||||
|
constexpr uint8_t param_request = 55;
|
||||||
|
constexpr uint8_t end = 255;
|
||||||
|
constexpr uint8_t discover = 1;
|
||||||
|
constexpr uint8_t subnet_mask = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct __attribute__((packed)) dhcp_discover {
|
||||||
|
uint8_t op = 1;
|
||||||
|
uint8_t htype = 1;
|
||||||
|
uint8_t hlen = 6;
|
||||||
|
uint8_t hops = 0;
|
||||||
|
uint32_t xid = __builtin_bswap32(0x12345678);
|
||||||
|
uint16_t secs = 0;
|
||||||
|
uint16_t flags = __builtin_bswap16(0x8000);
|
||||||
|
std::array<uint8_t, 4> ciaddr = {};
|
||||||
|
std::array<uint8_t, 4> yiaddr = {};
|
||||||
|
std::array<uint8_t, 4> siaddr = {};
|
||||||
|
std::array<uint8_t, 4> giaddr = {};
|
||||||
|
std::array<uint8_t, 16> chaddr = {};
|
||||||
|
std::array<uint8_t, 64> sname = {};
|
||||||
|
std::array<uint8_t, 128> file = {};
|
||||||
|
std::array<uint8_t, 4> magic = {99, 130, 83, 99};
|
||||||
|
uint8_t opt_msg_type[3] = {dhcp_opt::message_type, 1, dhcp_opt::discover};
|
||||||
|
uint8_t opt_params[3] = {dhcp_opt::param_request, 1, dhcp_opt::subnet_mask};
|
||||||
|
uint8_t opt_end = dhcp_opt::end;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(dhcp_discover) == 247);
|
||||||
|
|
||||||
|
static void send_discover(timer_queue& timers, const std::array<uint8_t, 6>& mac) {
|
||||||
|
auto sn = w6300::socket_id{0};
|
||||||
|
w6300::open_socket(sn, w6300::protocol::udp, w6300::port_num{68}, w6300::sock_flag::none);
|
||||||
|
|
||||||
|
dhcp_discover pkt;
|
||||||
|
std::copy(mac.begin(), mac.end(), pkt.chaddr.begin());
|
||||||
|
|
||||||
|
w6300::ip_address broadcast = {};
|
||||||
|
broadcast.ip = {255, 255, 255, 255};
|
||||||
|
broadcast.len = 4;
|
||||||
|
|
||||||
|
w6300::sendto(sn, std::span{reinterpret_cast<uint8_t*>(&pkt), sizeof(pkt)}, broadcast, w6300::port_num{67});
|
||||||
|
|
||||||
|
timers.schedule_ms(5000, [&timers, mac]() { send_discover(timers, mac); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcp_start(timer_queue& timers, const std::array<uint8_t, 6>& mac) {
|
||||||
|
send_discover(timers, mac);
|
||||||
|
}
|
||||||
5
include/dhcp.h
Normal file
5
include/dhcp.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <array>
|
||||||
|
#include "timer_queue.h"
|
||||||
|
|
||||||
|
void dhcp_start(timer_queue& timers, const std::array<uint8_t, 6>& mac);
|
||||||
58
include/sorted_list.h
Normal file
58
include/sorted_list.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <new>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
struct sorted_list {
|
||||||
|
struct node {
|
||||||
|
alignas(T) uint8_t storage[sizeof(T)];
|
||||||
|
node* next = nullptr;
|
||||||
|
|
||||||
|
T& value() { return *reinterpret_cast<T*>(storage); }
|
||||||
|
const T& value() const { return *reinterpret_cast<const T*>(storage); }
|
||||||
|
};
|
||||||
|
|
||||||
|
node nodes[N];
|
||||||
|
node* head = nullptr;
|
||||||
|
node* free_head = &nodes[0];
|
||||||
|
|
||||||
|
sorted_list() {
|
||||||
|
for (int i = 0; i < N - 1; i++) nodes[i].next = &nodes[i + 1];
|
||||||
|
nodes[N - 1].next = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return head == nullptr; }
|
||||||
|
bool full() const { return free_head == nullptr; }
|
||||||
|
|
||||||
|
T& front() { return head->value(); }
|
||||||
|
const T& front() const { return head->value(); }
|
||||||
|
|
||||||
|
void insert(T value) {
|
||||||
|
if (full()) return;
|
||||||
|
node* n = free_head;
|
||||||
|
free_head = n->next;
|
||||||
|
new (n->storage) T(std::move(value));
|
||||||
|
|
||||||
|
if (!head || n->value() < head->value()) {
|
||||||
|
n->next = head;
|
||||||
|
head = n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node* cur = head;
|
||||||
|
while (cur->next && !(n->value() < cur->next->value()))
|
||||||
|
cur = cur->next;
|
||||||
|
n->next = cur->next;
|
||||||
|
cur->next = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_front() {
|
||||||
|
if (empty()) return;
|
||||||
|
node* n = head;
|
||||||
|
head = n->next;
|
||||||
|
n->value().~T();
|
||||||
|
n->next = free_head;
|
||||||
|
free_head = n;
|
||||||
|
}
|
||||||
|
};
|
||||||
50
include/timer_queue.h
Normal file
50
include/timer_queue.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
|
#include "pico/time.h"
|
||||||
|
#include "sorted_list.h"
|
||||||
|
|
||||||
|
struct timer_entry {
|
||||||
|
absolute_time_t when;
|
||||||
|
std::function<void()> fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator<(const timer_entry& a, const timer_entry& b) {
|
||||||
|
return absolute_time_diff_us(b.when, a.when) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timer_queue {
|
||||||
|
sorted_list<timer_entry, 16> queue;
|
||||||
|
alarm_id_t alarm = -1;
|
||||||
|
|
||||||
|
void schedule(absolute_time_t when, std::function<void()> fn) {
|
||||||
|
queue.insert({when, std::move(fn)});
|
||||||
|
arm();
|
||||||
|
}
|
||||||
|
|
||||||
|
void schedule_ms(uint32_t ms, std::function<void()> fn) {
|
||||||
|
schedule(make_timeout_time_ms(ms), std::move(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
while (!queue.empty()) {
|
||||||
|
auto& front = queue.front();
|
||||||
|
if (absolute_time_diff_us(get_absolute_time(), front.when) > 0) break;
|
||||||
|
auto fn = std::move(front.fn);
|
||||||
|
queue.pop_front();
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
arm();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return queue.empty(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int64_t alarm_cb(alarm_id_t, void*) { return 0; }
|
||||||
|
|
||||||
|
void arm() {
|
||||||
|
if (alarm >= 0) cancel_alarm(alarm);
|
||||||
|
alarm = -1;
|
||||||
|
if (!queue.empty())
|
||||||
|
alarm = add_alarm_at(queue.front().when, alarm_cb, nullptr, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
7
main.cpp
7
main.cpp
@@ -4,22 +4,29 @@
|
|||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
#include "wire.h"
|
#include "wire.h"
|
||||||
#include "usb_cdc.h"
|
#include "usb_cdc.h"
|
||||||
|
#include "timer_queue.h"
|
||||||
|
#include "dhcp.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "w6300.h"
|
#include "w6300.h"
|
||||||
|
|
||||||
static usb_cdc usb;
|
static usb_cdc usb;
|
||||||
|
static timer_queue timers;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
tusb_init();
|
tusb_init();
|
||||||
|
|
||||||
net_init();
|
net_init();
|
||||||
|
|
||||||
|
auto ninfo = w6300::get_net_info();
|
||||||
|
dhcp_start(timers, ninfo.mac);
|
||||||
|
|
||||||
static static_vector<uint8_t, 256> rx_buf;
|
static static_vector<uint8_t, 256> rx_buf;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
tud_task();
|
tud_task();
|
||||||
|
|
||||||
usb.drain();
|
usb.drain();
|
||||||
|
timers.run();
|
||||||
|
|
||||||
while (tud_cdc_available()) {
|
while (tud_cdc_available()) {
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
|
|||||||
Reference in New Issue
Block a user