2024-10-15 19:26:19 +02:00
|
|
|
#include "cdc_class.h"
|
|
|
|
#include "usart.h"
|
|
|
|
#include "mirror.h"
|
2024-10-16 19:34:04 +02:00
|
|
|
|
|
|
|
static constexpr unsigned Timeout = 5000; // us
|
|
|
|
|
2024-10-15 19:26:19 +02:00
|
|
|
/** 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
|
2024-10-16 15:46:34 +02:00
|
|
|
* 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.
|
2024-10-15 19:26:19 +02:00
|
|
|
* */
|
2024-10-16 15:46:34 +02:00
|
|
|
class Middle : public BaseLayer {
|
|
|
|
static constexpr unsigned max = 128;
|
2024-10-17 13:36:01 +02:00
|
|
|
FIFO<char,max> rx_ring;
|
2024-10-16 15:46:34 +02:00
|
|
|
volatile unsigned index;
|
|
|
|
char buffer [max];
|
|
|
|
public:
|
2024-10-17 13:36:01 +02:00
|
|
|
explicit Middle () noexcept : BaseLayer(), rx_ring(), index(0u) {}
|
2024-10-16 15:46:34 +02:00
|
|
|
/* 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
|
2024-10-17 13:36:01 +02:00
|
|
|
* 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ů.
|
2024-10-16 15:46:34 +02:00
|
|
|
* */
|
|
|
|
uint32_t Up(const char * data, const uint32_t len) override {
|
2024-10-17 13:36:01 +02:00
|
|
|
for (unsigned n=0; n<len; n++) {
|
|
|
|
if (!rx_ring.Write (data[n])) break;
|
|
|
|
else index += 1u;
|
|
|
|
}
|
2024-10-16 15:46:34 +02:00
|
|
|
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 () {
|
2024-10-16 19:34:04 +02:00
|
|
|
/* Je to dost zjednodušeno, odešle se 64 bytový paket,
|
2024-10-17 13:36:01 +02:00
|
|
|
* nebo po 5 ms to co zůstalo ve frontě.
|
2024-10-16 15:46:34 +02:00
|
|
|
* */
|
2024-10-16 19:34:04 +02:00
|
|
|
if ((is_timeout() and index) or (index >= 64)) {
|
2024-10-17 13:36:01 +02:00
|
|
|
unsigned n;
|
|
|
|
for (n=0u; n<max; n++) {
|
|
|
|
if (!rx_ring.Read (buffer[n])) break;
|
|
|
|
}
|
|
|
|
if (!n) return;
|
|
|
|
index = 0u;
|
|
|
|
block(buffer, n);
|
2024-10-16 15:46:34 +02:00
|
|
|
}
|
|
|
|
}
|
2024-10-16 19:34:04 +02:00
|
|
|
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);
|
|
|
|
}
|
2024-10-16 15:46:34 +02:00
|
|
|
};
|
2024-10-15 19:26:19 +02:00
|
|
|
static cdc_class cdc;
|
|
|
|
static Usart usart;
|
|
|
|
static Mirror top;
|
2024-10-16 15:46:34 +02:00
|
|
|
static Middle mid;
|
2024-10-15 19:26:19 +02:00
|
|
|
int main () {
|
|
|
|
cdc.init();
|
|
|
|
top += cdc;
|
2024-10-16 15:46:34 +02:00
|
|
|
top -= mid += usart;
|
2024-10-15 19:26:19 +02:00
|
|
|
cdc.attach(usart);
|
2024-10-16 19:34:04 +02:00
|
|
|
set_timeout_us(Timeout);
|
2024-10-15 19:26:19 +02:00
|
|
|
for (;;) {
|
2024-10-16 15:46:34 +02:00
|
|
|
mid.pass();
|
2024-10-15 19:26:19 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|