sitara_depot/components/free_rtos/ethernet_ip/eth_udp_client.cpp

223 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* eth_udp_client.cpp
*
* Created on: 15 апреля. 2023 год.
* Author: sychev
*/
#include "free_rtos/ethernet_ip/eth_udp_client.hpp"
#include "free_rtos/base/swap.h"
#include "free_rtos/ethernet_ip/eth_ip_types.h"
#include "free_rtos/ethernet_ip/eth_checksum.h"
#include "free_rtos/ethernet_ip/eth_ip_prots_id.h"
#include <algorithm>
#include <cstring>
free_rtos::EthUpdClient::EthUpdClient(EthIpIface& ip_iface, EthArpIface& arp,
TEthMacPorts port_id, uint16_t port_dst_be, uint16_t port_src_be,
bool use_chksum) :
port_dst_be_{port_dst_be},
port_src_be_{port_src_be},
use_checksum_{use_chksum},
ip_iface_{ip_iface},
arp_{arp},
port_id_{port_id}
{ }
void free_rtos::EthUpdClient::put_data(uint8_t * p_data, uint32_t len)
{
if ((p_data == nullptr) || (len == 0)) {
return;
}
UDPToggle toggle = in_toggle_.exchange(UDPToggle::UDP_BUSY);
std::vector<uint8_t>& buff = buff_[toggle];
uint32_t new_size = buff.size() + len;
if(new_size > max_buf_size) {
in_toggle_.exchange(toggle);
EnetAppUtils_print("Warning ! UDP client buffer overflow !\r\n");
return;
}
buff.reserve(new_size);
buff.insert(buff.end(), p_data, p_data + len);
in_toggle_.exchange(toggle);
rx_sem_.post();
}
size_t free_rtos::EthUpdClient::get_data(uint8_t * p_data, uint32_t len)
{
std::vector<uint8_t>& buff = buff_[out_toggle_];
size_t size = buff.size();
if (size > len) {
size = len;
}
auto item_begin = buff.begin();
auto item_end = item_begin + size;
std::copy(item_begin, item_end, p_data);
buff.erase(item_begin, item_end);
return size;
}
bool free_rtos::EthUpdClient::capture_buffer()
{
UDPToggle desired = out_toggle_;
UDPToggle expected = static_cast<UDPToggle>((desired + 1)%UDPToggle::UDP_BUF_NUM);
if(in_toggle_.compare_exchange_weak(expected, desired) == false) {
return false;
}
out_toggle_ = expected;
return true;
}
size_t free_rtos::EthUpdClient::get_data_size()
{
size_t size = buff_[out_toggle_].size();
if (size == 0) {
if(capture_buffer() != false) {
size = buff_[out_toggle_].size();
}
}
return size;
}
int32_t free_rtos::EthUpdClient::read(uint8_t * p_data, uint32_t len)
{
if ((p_data == nullptr) || (len == 0)) {
return 0;
}
if(buff_[out_toggle_].size() == 0) {
while (capture_buffer() == false) {
rx_sem_.pend();
}
}
return get_data(p_data, len);
}
int32_t free_rtos::EthUpdClient::read_async(uint8_t * p_data, uint32_t len)
{
if ((p_data == nullptr) || (len == 0)) {
return 0;
}
if (buff_[out_toggle_].size() == 0) {
if(capture_buffer() == false) {
return 0;
}
}
return get_data(p_data, len);
}
void free_rtos::EthUpdClient::clear()
{
buff_[out_toggle_].clear();
while (capture_buffer() == false) {
rx_sem_.pend();
}
buff_[out_toggle_].clear();
}
bool free_rtos::EthUpdClient::write(uint32_t ip_dst_be, uint8_t * p_data, uint32_t len)
{
UDPHandlerArgs udpHandlerArgs;
uint64_t mac_dst{0x0000000000000000};
if (ip_dst_be == 0) {
ip_dst_be = src_ip_;
mac_dst = src_mac_;
} else {
if (arp_.getMacAddr(ip_dst_be, mac_dst) == false) {
return false;
}
}
//udpHandlerArgs.buffer = nullptr;
udpHandlerArgs.port_id = port_id_;
//udpHandlerArgs.stack_handler = nullptr;
udpHandlerArgs.ip_header_len = sizeof(TUdpHeader);
udpHandlerArgs.ip_data_len = len;
udpHandlerArgs.dest_ip = ip_dst_be;
udpHandlerArgs.dest_mac = mac_dst;
udpHandlerArgs.ip_prot_id = IP_PROT_UDP;
udpHandlerArgs.ip_handler = this;
udpHandlerArgs.p_data = p_data;
return ip_iface_.send(udpHandlerArgs);
}
uint16_t free_rtos::EthUpdClient::fill_udp_header(UDPHandlerArgs& udpHandlerArgs) {
uint16_t udp_len = udpHandlerArgs.ip_header_len + udpHandlerArgs.ip_data_len;
TUdpHeader * udp_hdr = (TUdpHeader *)(udpHandlerArgs.buffer + sizeof(TEthFrameHeader) + sizeof(TIpHeader));
TUdpHeader udp_header;
udp_header.Src_port = port_src_be_;
udp_header.Dst_port = port_dst_be_;
udp_header.Length = BASE_SWAP16(udp_len);
udp_header.Chk_sum = 0;
if (use_checksum_) {
uint32_t self_ip = ip_iface_.getSelfIpAddr();
uint32_t chk_sum32 = 0;
uint8_t * const dst_ip = (uint8_t *)&udpHandlerArgs.dest_ip;
uint8_t * const src_ip = (uint8_t *)&self_ip;
for (int j = 0; j < ETH_IP_ADDR_LEN; j += 2)
{
chk_sum32 += ((uint16_t)dst_ip[j] << 8) + dst_ip[j+1];
chk_sum32 += ((uint16_t)src_ip[j] << 8) + src_ip[j+1];
}
chk_sum32 += IP_PROT_UDP + udp_len;
//uint16_t chk_sum16 = eth_calcChksum2(chk_sum32, (uint8_t *)&udpHandlerArgs.udp_header, sizeof(TUdpHeader), (uint8_t *)udpHandlerArgs.p_data, udpHandlerArgs.ip_data_len);
//Расчет контрольной суммы совмещен с копированием данных !
uint16_t chk_sum16 = eth_calcChksum3(udp_hdr, chk_sum32,
&udp_header, sizeof(TUdpHeader),
udpHandlerArgs.p_data, udpHandlerArgs.ip_data_len);
udp_hdr->Chk_sum = BASE_SWAP16(chk_sum16);
} else {
uint8_t* udp_data = udpHandlerArgs.buffer + sizeof(TEthFrameHeader) + sizeof(TIpHeader) + sizeof(TUdpHeader);
*udp_hdr = udp_header;
memcpy(udp_data, udpHandlerArgs.p_data, udpHandlerArgs.ip_data_len);
}
return sizeof(TUdpHeader) + udpHandlerArgs.ip_data_len;
}
uint16_t free_rtos::EthUpdClient::Sender(HandlerArgs& handlerArgs, size_t scatter_segment)
{
UDPHandlerArgs& udpHandlerArgs = static_cast<UDPHandlerArgs&>(handlerArgs); // downcasting back to derived type
fill_udp_header(udpHandlerArgs);
return sizeof(TUdpHeader) + udpHandlerArgs.ip_data_len;
}
int32_t free_rtos::EthUpdClient::Process(uint8_t * p_data, uint32_t len)
{
put_data(p_data, len);
return 0;
}