SatCat5
cfgbus_hdlc.cc
1 // Copyright 2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/cfgbus_hdlc.h>
7 #include <satcat5/polling.h>
8 #include <satcat5/utils.h>
9 
10 using satcat5::cfg::Hdlc;
12 
13 // Define hardware register map.
14 static const unsigned REGADDR_IRQ = 0;
15 static const unsigned REGADDR_CFG = 1;
16 static const unsigned REGADDR_STATUS = 2;
17 static const unsigned REGADDR_DATA = 3;
18 
19 // Define control-register commands:
20 static const u32 CMD_EOF = 0x0100u;
21 
22 // Status and command codes for the multiserial control registers.
23 static const u32 MS_DVALID = (1u << 8);
24 static const u32 MS_RD_READY = (1u << 0);
25 static const u32 MS_CMD_FULL = (1u << 1);
26 
27 Hdlc::Hdlc(satcat5::cfg::ConfigBus* cfg, unsigned devaddr)
28  : BufferedIO(m_txbuff, SATCAT5_HDLC_BUFFSIZE, SATCAT5_HDLC_MAXPKT,
29  m_rxbuff, SATCAT5_HDLC_BUFFSIZE, 0)
30  , Interrupt(cfg, devaddr, REGADDR_IRQ)
31  , m_ctrl(cfg->get_register(devaddr))
32  , m_tx_eof(false)
33 {
34  // No other initialization at this time.
35 }
36 
38  unsigned clkref_hz,
39  unsigned baud_hz,
40  unsigned frame_bytes)
41 {
42  // Note: Writing to Config register also resets hardware FIFOs.
43  u32 clkdiv = div_round_u32(clkref_hz, baud_hz);
44  m_ctrl[REGADDR_CFG] = (frame_bytes << 16) | (clkdiv);
45 }
46 
48  // Forward data from Tx-FIFO to hardware.
49  unsigned rdy = src->get_read_ready();
50  while (m_tx_eof || rdy) {
51  // Any space in the command FIFO? If so, issue command (data or EOF).
52  u32 status = m_ctrl[REGADDR_STATUS];
53  if (status & MS_CMD_FULL) break;
54  if (m_tx_eof) {
55  m_ctrl[REGADDR_DATA] = CMD_EOF;
56  m_tx_eof = false;
57  } else {
58  m_ctrl[REGADDR_DATA] = src->read_u8();
59  if (--rdy == 0) { m_tx_eof = true; }
60  }
61  }
62  // End of data? Always finalize to avoid getting stuck in limbo.
63  if (!rdy) src->read_finalize();
64  // Do we need to schedule follow-up for trailing EOF?
65  // (The command FIFO may fill before we can write CMD_EOF.)
66  if (m_tx_eof) { timer_every(1); } else { timer_stop(); }
67 }
68 
70  // Read any data waiting in the hardware FIFO.
71  // (Let PacketBuffer object handle overflow, if it occurs.)
72  unsigned nwrite = 0;
73  while (1) {
74  u32 data = m_ctrl[REGADDR_DATA];
75  if (data & MS_DVALID) {
76  u8 byte = (u8)(data & 0xFF);
77  m_rx.write_u8(byte);
78  ++nwrite;
79  } else {
80  break;
81  }
82  }
83 
84  // Finalize new data to ensure downstream notifications.
85  if (nwrite) m_rx.write_finalize();
86 }
87 
89  // Trailing EOF: Write the command as soon as the FIFO has space.
90  // (We may not get another data_rcvd() notification.)
91  data_rcvd(&satcat5::io::null_read);
92 }
Generic ConfigBus API.
Definition: cfgbus_core.h:124
Interface driver for the cfgbus_hdlc block.
Definition: cfgbus_hdlc.h:30
void irq_event()
Interrupt service routine.
Definition: cfgbus_hdlc.cc:69
void configure(unsigned clkref_hz, unsigned baud_hz, unsigned frame_bytes=0)
Configure the HDLC driver.
Definition: cfgbus_hdlc.cc:37
void timer_event()
Child class MUST override this method.
Definition: cfgbus_hdlc.cc:88
void data_rcvd(satcat5::io::Readable *src)
The data_rcvd() callback is polled whenever data is available.
Definition: cfgbus_hdlc.cc:47
Event-handler for individual ConfigBus interrupts.
satcat5::io::PacketBuffer m_rx
Receive data (user reads, child writes)
Definition: io_buffer.h:60
bool write_finalize() override
Mark end of frame and release temporary working data.
Definition: pkt_buffer.cc:105
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 void read_finalize()
Consume any remaining bytes in this frame, if applicable.
Definition: io_readable.cc:270
virtual unsigned get_read_ready() const =0
How many bytes can be read without blocking?
void write_u8(u8 data)
One of many functions for writing integer/floating point values, see details.
Definition: io_writeable.cc:20
void timer_stop()
Stop all future notifications.
Definition: polling.cc:326
void timer_every(unsigned msec)
Configure a repeating notification every X milliseconds.
Definition: polling.cc:321
Core event-processing loop for SatCat5 software.
Miscellaneous mathematical utility functions.
constexpr u32 div_round_u32(u32 a, u32 b)
Integer division functions with various rounding options:
Definition: utils.h:272