SatCat5
net_aeroftp.cc
1 // Copyright 2024 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/eth_dispatch.h>
7 #include <satcat5/log.h>
8 #include <satcat5/net_aeroftp.h>
9 #include <satcat5/udp_dispatch.h>
10 #include <satcat5/utils.h>
11 
12 // Define the protocol-specific wrappers first.
14  : satcat5::eth::AddressContainer(eth)
15  , satcat5::net::AeroFtpClient(&m_addr)
16 {
17  // Nothing else to initialize.
18 }
19 
21  : satcat5::udp::AddressContainer(udp)
22  , satcat5::net::AeroFtpClient(&m_addr)
23 {
24  // Nothing else to initialize.
25 }
26 
27 // From this point on, "AeroFtpClient" refers to the generic version.
29 using satcat5::log::Log;
31 using satcat5::util::div_ceil;
32 using satcat5::util::max_unsigned;
33 using satcat5::util::min_unsigned;
34 
35 static constexpr unsigned BLOCK_BYTES = 1024;
36 
37 static constexpr unsigned bytes2words(unsigned bytes)
38  { return div_ceil(bytes, 4u); }
39 static constexpr unsigned bytes2blocks(unsigned bytes)
40  { return div_ceil(bytes, BLOCK_BYTES); }
41 
43  : m_dst(dst)
44  , m_src(0)
45  , m_aux(0)
46  , m_file_id(0)
47  , m_file_len(0)
48  , m_file_pos(0)
49  , m_bytes_sent(0)
50  , m_throttle(1)
51 {
52  // Nothing else to initialize.
53 }
54 
56 {
57  m_dst->close();
58  end_of_file();
59 }
60 
62 {
63  if (m_src) m_src->read_finalize();
64  if (m_aux) m_aux->read_finalize();
65  m_src = 0;
66  m_aux = 0;
67  m_file_id = 0;
68  m_file_len = 0;
69  m_file_pos = 0;
70  timer_stop();
71 }
72 
73 bool AeroFtpClient::send(u32 file_id, Readable* src, Readable* aux)
74 {
75  // Sanity check: Must be idle before starting a new file.
76  if (busy()) return false;
77 
78  // Sanity check: The primary input must be non-empty.
79  if (!(src && src->get_read_ready())) return false;
80 
81  // Sanity check: If auxiliary source is provided, the lengths must match.
82  if (aux) {
83  unsigned src_blocks = bytes2blocks(src->get_read_ready());
84  unsigned aux_blocks = aux->get_read_ready();
85  if (src_blocks != aux_blocks) return false;
86  }
87 
88  // Reset transmit state.
89  m_src = src;
90  m_aux = aux;
91  m_file_id = file_id;
92  m_file_len = src->get_read_ready();
93  m_file_pos = 0;
94  m_bytes_sent = 0;
95  if (m_aux) skip_ahead();
96 
97  // If there's any data left, send the first packet.
98  if (!done()) timer_event();
99  return true;
100 }
101 
103 {
104  // For each "0" in the aux stream, discard an input block.
105  while (m_aux->get_read_ready() && !m_aux->read_u8()) {
106  m_src->read_consume(BLOCK_BYTES);
107  m_file_pos += BLOCK_BYTES;
108  }
109 }
110 
111 void AeroFtpClient::throttle(unsigned msec_per_pkt)
112 {
113  // Note: Leave timer state as-is; new setting applies after next packet.
114  m_throttle = max_unsigned(1, msec_per_pkt);
115 }
116 
118 {
119  // Ignore stray timer events that occur after close().
120  if (!m_src) return;
121 
122  // Calculate length for the next packet.
123  unsigned next_bytes = min_unsigned(BLOCK_BYTES, m_file_len - m_file_pos);
124  unsigned next_words = bytes2words(next_bytes);
125 
126  // Are we able to send data right now?
127  satcat5::io::Writeable* wr = m_dst->open_write(16 + 4*next_words);
128  if (wr) {
129  // Write the transfer header.
130  wr->write_u32(m_file_id);
131  wr->write_u32(bytes2words(m_file_len));
132  wr->write_u32(bytes2words(m_file_pos));
133  wr->write_u32(next_words);
134 
135  // Copy the next block of data.
136  u8 temp[BLOCK_BYTES];
137  m_src->read_bytes(next_bytes, temp);
138  wr->write_bytes(next_bytes, temp);
139 
140  // Zero-pad to word boundary if needed.
141  unsigned pad = 4*next_words - next_bytes;
142  while (pad--) {wr->write_u8(0);}
143  bool ok = wr->write_finalize();
144 
145  // Get ready for the next packet.
146  if (!ok) Log(satcat5::log::WARNING, "AeroFTP: Tx drop at offset").write(m_file_pos);
147  m_file_pos += BLOCK_BYTES;
148  m_bytes_sent += 4*next_words;
149  if (m_aux) skip_ahead();
150  }
151 
152  // Continue transmission?
153  if (done()) {
154  Log(satcat5::log::INFO, "AeroFTP: Transmission complete, ID")
156  end_of_file();
157  } else {
159  }
160 }
Inheritable container for a eth::Address.
Definition: eth_address.h:60
Implement AeroFTP protocol over Ethernet.
Definition: net_aeroftp.h:93
AeroFtpClient(satcat5::eth::Dispatch *eth)
Constructor links to the Ethernet interface.
Definition: net_aeroftp.cc:13
Implemention of "net::Dispatch" for Ethernet frames.
Definition: eth_dispatch.h:21
Abstract API for reading byte-streams and packets.
Definition: io_readable.h:68
u8 read_u8()
One of many functions for reading integer/floating point values, see details.
Definition: io_readable.cc:44
virtual bool read_bytes(unsigned nbytes, void *dst)
Read 0 or more bytes into a buffer.
Definition: io_readable.cc:190
virtual void read_finalize()
Consume any remaining bytes in this frame, if applicable.
Definition: io_readable.cc:270
virtual bool read_consume(unsigned nbytes)
Read and discard 0 or more bytes.
Definition: io_readable.cc:204
virtual unsigned get_read_ready() const =0
How many bytes can be read without blocking?
Abstract API for writing byte-streams and packets.
Definition: io_writeable.h:24
virtual void write_bytes(unsigned nbytes, const void *src)
Write 0 or more bytes from a buffer.
void write_u8(u8 data)
One of many functions for writing integer/floating point values, see details.
Definition: io_writeable.cc:20
virtual bool write_finalize()
Mark end of frame and release temporary working data.
The Log class creates and formats one log message.
Definition: log.h:195
Log & write10(s32 val)
Print integer as a decimal value with no leading zeros.
Definition: log.cc:261
Log & write(const char *str)
Formatting methods for various data types.
Definition: log.cc:198
Defines a generic API for sending data to a specific destination, such as a MAC address,...
Definition: net_address.h:30
virtual satcat5::io::Writeable * open_write(unsigned len)=0
Open a new frame to the designated address and type.
virtual void close()=0
Close any open connections and revert to idle.
AeroCube File Transfer Protocol (AeroFTP) transmitter.
Definition: net_aeroftp.h:42
u32 m_file_len
Length (bytes)
Definition: net_aeroftp.h:78
bool done() const
Is the current transfer completed?
Definition: net_aeroftp.h:47
u32 m_file_pos
Current read index (bytes)
Definition: net_aeroftp.h:79
satcat5::io::Readable * m_src
Source for file data.
Definition: net_aeroftp.h:75
bool send(u32 file_id, satcat5::io::Readable *src, satcat5::io::Readable *aux=0)
Begin transmission of the designated file.
Definition: net_aeroftp.cc:73
void timer_event() override
Callback for timer events.
Definition: net_aeroftp.cc:117
void skip_ahead()
Skip to next requested block.
Definition: net_aeroftp.cc:102
void throttle(unsigned msec_per_pkt)
Set throttle (one packet every N msec).
Definition: net_aeroftp.cc:111
satcat5::io::Readable * m_aux
Source for retransmit control.
Definition: net_aeroftp.h:76
void close()
Close connection and abort transfer in progress.
Definition: net_aeroftp.cc:55
void end_of_file()
End-of-file cleanup.
Definition: net_aeroftp.cc:61
unsigned m_throttle
Delay per packet (msec)
Definition: net_aeroftp.h:81
u32 m_file_id
ID for this file.
Definition: net_aeroftp.h:77
u32 m_bytes_sent
Count transmission length.
Definition: net_aeroftp.h:80
bool busy() const
Is there already a transfer in progress?
Definition: net_aeroftp.h:45
void timer_stop()
Stop all future notifications.
Definition: polling.cc:326
void timer_once(unsigned msec)
Configure a one-time notification after X milliseconds.
Definition: polling.cc:316
Inheritable container for a udp::Address.
Definition: udp_core.h:149
Implement AeroFTP protocol over UDP.
Definition: net_aeroftp.h:121
AeroFtpClient(satcat5::udp::Dispatch *udp)
Constructor links to the UDP stack.
Definition: net_aeroftp.cc:20
Dispatcher sorts incoming UDP messages by port index.
Definition: udp_dispatch.h:20
Diagnostic logging to UART and/or Ethernet ports.
Miscellaneous mathematical utility functions.