RISC-V/V203/usb/usart/main.cpp
2024-10-17 13:36:01 +02:00

87 lines
2.8 KiB
C++

#include "cdc_class.h"
#include "usart.h"
#include "mirror.h"
static constexpr unsigned Timeout = 5000; // us
/** Převodník USB_CDC - USART
* Datový formát je pevný - 8 bit, 1 stop bit, bez parity.
* Změnu po USB by šlo dost jednoduše dodělat, ale nepovažoval jsem to za nutné.
* Baudová rychlost se dá po USB změnit na libovolnou hodnotu.
*
* Výhoda tohoto řešení je, že nad USARTem může běžet nějaký protokol
* přímo v tomto čipu. Jinak je to asi nejlevnější řešení.
*
* @class Middle
* Zkracuje obsluhu přerušení od USART1 čímž podstatně zlepší činnost
* v plném duplexu. Je možné jí z řetězce vyhodit. Je to také ukázka
* jak přidat funkci (třeba vlastní protokol) do řetězce.
* */
class Middle : public BaseLayer {
static constexpr unsigned max = 128;
FIFO<char,max> rx_ring;
volatile unsigned index;
char buffer [max];
public:
explicit Middle () noexcept : BaseLayer(), rx_ring(), index(0u) {}
/* Up() v původním řetězci volalo fakticky Down() v cdc_class.
* Vzhledem k tomu, že len je zde 1 a USB musí vyvolat odeslání
* paketu, zdržuje to a přerušení zde může být ignorováno.
* Tohle ho významně zkrátí, ale zase musí být v hlavní smyčce
* odeslání dat pomocí metody pass(). Ukázalo se, že je nutné
* předávat data přes další frontu. Pak to funguje full duplex
* na rychlosti 4 MBd bez ztráty znaků.
* */
uint32_t Up(const char * data, const uint32_t len) override {
for (unsigned n=0; n<len; n++) {
if (!rx_ring.Write (data[n])) break;
else index += 1u;
}
return len;
}
// Down je průchozí, bylo by možné toto zcela vypustit.
uint32_t Down(const char * data, const uint32_t len) override {
return BaseLayer::Down(data, len);
}
/* Vlastní odeslání paketu na USB_CDC
* */
void pass () {
/* Je to dost zjednodušeno, odešle se 64 bytový paket,
* nebo po 5 ms to co zůstalo ve frontě.
* */
if ((is_timeout() and index) or (index >= 64)) {
unsigned n;
for (n=0u; n<max; n++) {
if (!rx_ring.Read (buffer[n])) break;
}
if (!n) return;
index = 0u;
block(buffer, n);
}
}
protected:
void block (const char * data, const uint32_t len) {
unsigned ofs = 0, rem = len;
while (rem) {
const unsigned n = BaseLayer::Up(data + ofs, rem);
rem -= n;
ofs += n;
}
set_timeout_us(Timeout);
}
};
static cdc_class cdc;
static Usart usart;
static Mirror top;
static Middle mid;
int main () {
cdc.init();
top += cdc;
top -= mid += usart;
cdc.attach(usart);
set_timeout_us(Timeout);
for (;;) {
mid.pass();
}
return 0;
}