Skip to content

Implement packed based receive API for UDP packets. #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions examples/UDP_Client/UDP_Client.ino
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ static T1SMacSettings const t1s_default_mac_settings;
static IPAddress const UDP_SERVER_IP_ADDR = {192, 168, 42, 100 + 0};
static uint16_t const UDP_CLIENT_PORT = 8889;
static uint16_t const UDP_SERVER_PORT = 8888;
static uint8_t udp_tx_msg_buf[256] = {0};
static uint8_t udp_rx_msg_buf[256] = {0};

/**************************************************************************************
* GLOBAL VARIABLES
Expand Down Expand Up @@ -123,6 +121,7 @@ void loop()
prev_udp_packet_sent = now;

/* Prepare UDP packet. */
uint8_t udp_tx_msg_buf[256] = {0};
int const tx_packet_size = snprintf((char *)udp_tx_msg_buf, sizeof(udp_tx_msg_buf), "Single-Pair Ethernet / 10BASE-T1S: packet cnt = %d", tx_packet_cnt);

/* Send a UDP packet to the UDP server. */
Expand All @@ -143,7 +142,7 @@ void loop()
int const rx_packet_size = udp_client.parsePacket();
if (rx_packet_size)
{
/* Receive incoming UDP packets. */
/* Print some metadata from received UDP packet. */
Serial.print("Received ");
Serial.print(rx_packet_size);
Serial.print(" bytes from ");
Expand All @@ -152,15 +151,27 @@ void loop()
Serial.print(udp_client.remotePort());
Serial.println();

int const bytes_read = udp_client.read(udp_rx_msg_buf, sizeof(udp_rx_msg_buf));
if (bytes_read > 0) {
udp_rx_msg_buf[bytes_read] = 0;
}
Serial.print("[");
Serial.print(millis());
Serial.print("] UDP_Client received packet content: \"");
Serial.print(reinterpret_cast<char *>(udp_rx_msg_buf));

/* Read from received UDP packet. */
size_t const UDP_RX_MSG_BUF_SIZE = 16 + 1; /* Reserve the last byte for the '\0' termination. */
uint8_t udp_rx_msg_buf[UDP_RX_MSG_BUF_SIZE] = {0};
int bytes_read = udp_client.read(udp_rx_msg_buf, UDP_RX_MSG_BUF_SIZE - 1);
while(bytes_read != 0)
{
/* Print received data to Serial. */
udp_rx_msg_buf[bytes_read] = '\0'; /* Terminate buffer so that we can print it as a C-string. */
Serial.print(reinterpret_cast<char *>(udp_rx_msg_buf));

/* Continue reading. */
bytes_read = udp_client.read(udp_rx_msg_buf, UDP_RX_MSG_BUF_SIZE - 1);
}
Serial.println("\"");

/* Finish reading the current packet. */
udp_client.flush();
}
}

Expand Down
44 changes: 32 additions & 12 deletions examples/UDP_Server/UDP_Server.ino
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ static T1SPlcaSettings const t1s_plca_settings{T1S_PLCA_NODE_ID};
static T1SMacSettings const t1s_default_mac_settings;

static uint16_t const UDP_SERVER_LOCAL_PORT = 8888;
static uint8_t udp_rx_msg_buf[256] = {0};

/**************************************************************************************
* GLOBAL VARIABLES
Expand Down Expand Up @@ -119,29 +118,50 @@ void loop()
}

/* Check for incoming UDP packets. */
int const packet_size = udp_server.parsePacket();
if (packet_size)
int const rx_packet_size = udp_server.parsePacket();
if (rx_packet_size)
{
/* Receive incoming UDP packets. */
std::vector<uint8_t> udp_tx_buf;
IPAddress const destination_ip = udp_server.remoteIP();
uint16_t const destination_port = udp_server.remotePort();

/* Print some metadata from received UDP packet. */
Serial.print("Received ");
Serial.print(packet_size);
Serial.print(rx_packet_size);
Serial.print(" bytes from ");
Serial.print(udp_server.remoteIP());
Serial.print(" port ");
Serial.print(udp_server.remotePort());
Serial.println();

int const bytes_read = udp_server.read(udp_rx_msg_buf, sizeof(udp_rx_msg_buf));
if (bytes_read > 0) {
udp_rx_msg_buf[bytes_read] = 0;
Serial.print("[");
Serial.print(millis());
Serial.print("] UDP_Client received packet content: \"");

/* Read from received UDP packet. */
size_t const UDP_RX_MSG_BUF_SIZE = 16 + 1; /* Reserve the last byte for the '\0' termination. */
uint8_t udp_rx_msg_buf[UDP_RX_MSG_BUF_SIZE] = {0};
int bytes_read = udp_server.read(udp_rx_msg_buf, UDP_RX_MSG_BUF_SIZE - 1);
while(bytes_read != 0)
{
/* Copy received data into transmit buffer for echo functionality. */
std::copy(udp_rx_msg_buf, udp_rx_msg_buf + bytes_read, std::back_inserter(udp_tx_buf));

/* Print received data to Serial. */
udp_rx_msg_buf[bytes_read] = '\0'; /* Terminate buffer so that we can print it as a C-string. */
Serial.print(reinterpret_cast<char *>(udp_rx_msg_buf));

/* Continue reading. */
bytes_read = udp_server.read(udp_rx_msg_buf, UDP_RX_MSG_BUF_SIZE - 1);
}
Serial.print("UDP_Server received packet content: \"");
Serial.print(reinterpret_cast<char *>(udp_rx_msg_buf));
Serial.println("\"");

/* Finish reading the current packet. */
udp_server.flush();

/* Send back a reply, to the IP address and port we got the packet from. */
udp_server.beginPacket(udp_server.remoteIP(), udp_server.remotePort());
udp_server.write((const uint8_t *)udp_rx_msg_buf, packet_size);
udp_server.beginPacket(destination_ip, destination_port);
udp_server.write(udp_tx_buf.data(), udp_tx_buf.size());
udp_server.endPacket();
}
}
Expand Down
80 changes: 50 additions & 30 deletions src/Arduino_10BASE_T1S_UDP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ static void lwIp_udp_raw_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, co

Arduino_10BASE_T1S_UDP::Arduino_10BASE_T1S_UDP()
: _udp_pcb{nullptr}
, _remote_ip{0,0,0,0}
, _remote_port{0}
, _send_to_ip{0,0,0,0}
, _send_to_port{0}
{
Expand Down Expand Up @@ -131,77 +129,99 @@ size_t Arduino_10BASE_T1S_UDP::write(uint8_t data)

size_t Arduino_10BASE_T1S_UDP::write(const uint8_t * buffer, size_t size)
{
_tx_data.reserve(_tx_data.size() + size);
std::copy(buffer, buffer + size, std::back_inserter(_tx_data));
return size;
}

int Arduino_10BASE_T1S_UDP::parsePacket()
{
return available();
if (_rx_pkt_list.size())
return _rx_pkt_list.front()->totalSize();
else
return 0;
}

int Arduino_10BASE_T1S_UDP::available()
{
return _rx_data.size();
if (_rx_pkt_list.size())
return _rx_pkt_list.front()->available();
else
return 0;
}

int Arduino_10BASE_T1S_UDP::read()
{
uint8_t const data = _rx_data.front();
_rx_data.pop_front();
return data;
if (_rx_pkt_list.size())
return _rx_pkt_list.front()->read();
else
return -1;
}

int Arduino_10BASE_T1S_UDP::read(unsigned char* buffer, size_t len)
{
size_t bytes_read = 0;
for (; bytes_read < len && !_rx_data.empty(); bytes_read++)
{
buffer[bytes_read] = _rx_data.front();
_rx_data.pop_front();
}
return bytes_read;
if (_rx_pkt_list.size())
return _rx_pkt_list.front()->read(buffer, len);
else
return -1;
}

int Arduino_10BASE_T1S_UDP::read(char* buffer, size_t len)
{
return read((unsigned char*)buffer, len);
if (_rx_pkt_list.size())
return _rx_pkt_list.front()->read(buffer, len);
else
return -1;
}

int Arduino_10BASE_T1S_UDP::peek()
{
return _rx_data.front();
if (_rx_pkt_list.size())
return _rx_pkt_list.front()->peek();
else
return -1;
}

void Arduino_10BASE_T1S_UDP::flush()
{
/* Nothing to be done. */
/* Drop packet from receive buffer. */
if (_rx_pkt_list.size())
_rx_pkt_list.pop_front();
}

IPAddress Arduino_10BASE_T1S_UDP::remoteIP()
{
return _remote_ip;
if (_rx_pkt_list.size())
return _rx_pkt_list.front()->remoteIP();
else
return IPAddress();
}

uint16_t Arduino_10BASE_T1S_UDP::remotePort()
{
return _remote_port;
if (_rx_pkt_list.size())
return _rx_pkt_list.front()->remotePort();
else
return 0;
}

void Arduino_10BASE_T1S_UDP::onUdpRawRecv(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, uint16_t port)
{
/* Obtain remote port and remote IP. */
_remote_ip = IPAddress(ip4_addr1(addr),
ip4_addr2(addr),
ip4_addr3(addr),
ip4_addr4(addr));
_remote_port = port;

/* Copy data into buffer. */
std::copy((uint8_t *)p->payload,
(uint8_t *)p->payload + p->len,
std::back_inserter(_rx_data));
auto const remote_ip = IPAddress(
ip4_addr1(addr),
ip4_addr2(addr),
ip4_addr3(addr),
ip4_addr4(addr));
auto const remote_port = port;

/* Create UDP object. */
auto const rx_pkt = std::make_shared<UdpRxPacket>(
remote_ip,
remote_port,
(uint8_t const *)p->payload,
p->len);

_rx_pkt_list.push_back(rx_pkt);

/* Free pbuf */
pbuf_free(p);
Expand Down
71 changes: 67 additions & 4 deletions src/Arduino_10BASE_T1S_UDP.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
* INCLUDE
**************************************************************************************/

#include <list>
#include <deque>
#include <vector>
#include <memory>

#include <api/Udp.h>
#include <api/IPAddress.h>
Expand Down Expand Up @@ -67,13 +69,74 @@ class Arduino_10BASE_T1S_UDP : public UDP


private:
/* LWIP */
struct udp_pcb * _udp_pcb;

IPAddress _remote_ip;
uint16_t _remote_port;
std::deque<uint8_t> _rx_data;

/* UDP TRANSMISSION */
IPAddress _send_to_ip;
uint16_t _send_to_port;
std::vector<uint8_t> _tx_data;

/* UDP RECEPTION */
class UdpRxPacket
{
private:
IPAddress const _remote_ip;
uint16_t const _remote_port;
size_t const _rx_data_len;
std::deque<uint8_t> _rx_data;

public:
UdpRxPacket(
IPAddress const remote_ip,
uint16_t const remote_port,
uint8_t const * p_data,
size_t const data_len)
: _remote_ip(remote_ip)
, _remote_port(remote_port)
, _rx_data_len(data_len)
, _rx_data(p_data, p_data + data_len)
{
}

typedef std::shared_ptr<UdpRxPacket> SharedPtr;

IPAddress remoteIP() const { return _remote_ip; }
uint16_t remotePort() const { return _remote_port; }
size_t totalSize() const { return _rx_data_len; }

int available()
{
return _rx_data.size();
}

int read()
{
uint8_t const data = _rx_data.front();
_rx_data.pop_front();
return data;
}

int read(unsigned char* buffer, size_t len)
{
size_t bytes_read = 0;
for (; bytes_read < len && !_rx_data.empty(); bytes_read++)
{
buffer[bytes_read] = _rx_data.front();
_rx_data.pop_front();
}
return bytes_read;
}

int read(char* buffer, size_t len)
{
return read((unsigned char*)buffer, len);
}

int peek()
{
return _rx_data.front();
}
};
std::list<UdpRxPacket::SharedPtr> _rx_pkt_list;
};