Compare commits

..

2 commits

Author SHA1 Message Date
Kizarm
b345a72511 refactoring usb 2024-10-14 17:09:39 +02:00
Kizarm
34e58e1b2b add ctrl interface 2024-10-14 16:50:40 +02:00
22 changed files with 312 additions and 155 deletions

View file

@ -4,7 +4,7 @@ TOOL ?= gcc
PRJ = example PRJ = example
VPATH = . ./$(TARGET) VPATH = . ./$(TARGET) ./common
BLD = ./build/ BLD = ./build/
DFLAGS = -d DFLAGS = -d
LFLAGS = -g LFLAGS = -g
@ -12,7 +12,7 @@ LDLIBS =
BFLAGS = --strip-unneeded BFLAGS = --strip-unneeded
CFLAGS = -MMD -Wall -Wno-parentheses -ggdb -fno-exceptions -ffunction-sections -fdata-sections CFLAGS = -MMD -Wall -Wno-parentheses -ggdb -fno-exceptions -ffunction-sections -fdata-sections
CFLAGS+= -I. -I./$(TARGET) CFLAGS+= -I. -I./$(TARGET) -I./common
DEL = rm -f DEL = rm -f
# zdrojaky # zdrojaky

1
V203/usb/cdc/ch32v203 Symbolic link
View file

@ -0,0 +1 @@
../ch32v203/

View file

@ -1,94 +0,0 @@
#ifndef CDC_CLASS_H
#define CDC_CLASS_H
#include "baselayer.h"
#include "gpio.h"
#include "fifo.h"
#include "system.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include "usb_desc.h"
#include "ch32v20x_usb.h"
/******************************************************************************/
/* Global Define */
/* end-point number */
#define DEF_UEP_IN 0x80
#define DEF_UEP_OUT 0x00
#define DEF_UEP0 0x00
#define DEF_UEP1 0x01
#define DEF_UEP2 0x02
#define DEF_UEP3 0x03
#define DEF_UEP4 0x04
#define DEF_UEP5 0x05
#define DEF_UEP6 0x06
#define DEF_UEP7 0x07
#define DEF_UEP_NUM 8
#define USBFSD_UEP_MOD_BASE 0x5000000C
#define USBFSD_UEP_DMA_BASE 0x50000010
#define USBFSD_UEP_LEN_BASE 0x50000030
#define USBFSD_UEP_CTL_BASE 0x50000032
#define USBFSD_UEP_RX_EN 0x08
#define USBFSD_UEP_TX_EN 0x04
#define USBFSD_UEP_BUF_MOD 0x01
#define DEF_UEP_DMA_LOAD 0 /* Direct the DMA address to the data to be processed */
#define DEF_UEP_CPY_LOAD 1 /* Use memcpy to move data to a buffer */
#define USBFSD_UEP_MOD(n) (*((volatile uint8_t *)(USBFSD_UEP_MOD_BASE+n)))
#define USBFSD_UEP_CTRL(n) (*((volatile uint8_t *)(USBFSD_UEP_CTL_BASE+n*0x04)))
#define USBFSD_UEP_DMA(n) (*((volatile uint32_t *)(USBFSD_UEP_DMA_BASE+n*0x04)))
#define USBFSD_UEP_BUF(n) ((uint8_t *)(*((volatile uint32_t *)(USBFSD_UEP_DMA_BASE+n*0x04)))+0x20000000)
#define USBFSD_UEP_TLEN(n) (*((volatile uint16_t *)(USBFSD_UEP_LEN_BASE+n*0x04)))
/* Setup Request Packets */
#define pUSBFS_SetupReqPak ((PUSB_SETUP_REQ)USBFS_EP0_Buf)
#ifdef __cplusplus
};
#endif
/** @class cdc_class
* V postatě je to převzato z originálního balíku od wch.nc, ale ten
* je napsán dost "špagetově", interface je nesrozumitelné, takže je tam dost věcí
* přidáno odhadem.
*/
class cdc_class : public BaseLayer {
GpioClass dtr;
FIFO<char, 128> TxRing;
bool Ready;
const uint8_t * pUSBFS_Descr;
/* Setup Request */
volatile uint8_t USBFS_SetupReqCode;
volatile uint8_t USBFS_SetupReqType;
volatile uint16_t USBFS_SetupReqValue;
volatile uint16_t USBFS_SetupReqIndex;
volatile uint16_t USBFS_SetupReqLen;
/* USB Device Status */
volatile uint8_t USBFS_DevConfig;
volatile uint8_t USBFS_DevAddr;
volatile uint8_t USBFS_DevSleepStatus;
volatile uint8_t USBFS_DevEnumStatus;
/* Endpoint Buffer */
__attribute__ ((aligned(4))) uint8_t USBFS_EP0_Buf[ DEF_USBD_UEP0_SIZE ];
__attribute__ ((aligned(4))) uint8_t USBFS_EP1_Buf[ DEF_USBD_ENDP1_SIZE ];
__attribute__ ((aligned(4))) uint8_t USBFS_EP2_Buf[ DEF_USBD_ENDP2_SIZE ];
__attribute__ ((aligned(4))) uint8_t USBFS_EP3_Buf[ DEF_USBD_ENDP3_SIZE ];
/* USB IN Endpoint Busy Flag */
volatile uint8_t USBFS_Endp_Busy[ DEF_UEP_NUM ];
public:
explicit cdc_class () noexcept;
void init ();
void cdc_irq ();
/// Předěláno na neblokující, data se vyměňují přes FIFO, rychlejší
uint32_t Down(const char * data, const uint32_t len) override;
protected:
void USBFS_Device_Init( bool sta );
void USBFS_Device_Endp_Init ();
void TxDataDeal ();
void TransferHandler ();
void InTokenHandler (const uint8_t intst);
void OutTokenHandler (const uint8_t intst);
void SetupTokenHandler ();
};
#endif // CDC_CLASS_H

1
V203/usb/cdc/common Symbolic link
View file

@ -0,0 +1 @@
../common/

View file

@ -1,31 +1,28 @@
#include "cdc_class.h" #include "cdc_class.h"
#include "system.h" #include "system.h"
typedef __SIZE_TYPE__ size_t;
/* Only one instance of this class ! */
static cdc_class * pInstance = nullptr; static cdc_class * pInstance = nullptr;
/* Interrupt Service Routine Declaration*/ extern "C" {
extern "C" void USBFS_IRQHandler(void) __attribute__((interrupt)); /* Interrupt Service Routine Declaration*/
[[gnu::interrupt]] void USBFS_IRQHandler();
/* prototype from libc, (hack.c), clang needed */
void * memcpy (void * dest, const void * src, size_t n);
};
/* Interrupt Service Routine Definition */
void USBFS_IRQHandler () { void USBFS_IRQHandler () {
if (pInstance) pInstance->cdc_irq(); if (pInstance) pInstance->cdc_irq();
} }
/* USB_Device_clock_source */ /* USB_Device_clock_source */
#define RCC_USBCLKSource_PLLCLK_Div1 ((uint8_t)0x00) enum RCC_USB_CLK_SRC : uint32_t {
#define RCC_USBCLKSource_PLLCLK_Div2 ((uint8_t)0x01) RCC_USBCLKSource_PLLCLK_Div1 = 0u,
#define RCC_USBCLKSource_PLLCLK_Div3 ((uint8_t)0x02) RCC_USBCLKSource_PLLCLK_Div2,
#define RCC_AHBPeriph_USBFS ((uint32_t)0x00001000) RCC_USBCLKSource_PLLCLK_Div3,
#define RCC_AHBPeriph_OTG_FS RCC_AHBPeriph_USBFS };
enum FunctionalState {DISABLE = 0, ENABLE};
static void RCC_USBCLKConfig(uint32_t RCC_USBCLKSource) { static void RCC_USBCLKConfig(const RCC_USB_CLK_SRC RCC_USBCLKSource) {
RCC.CFGR0.B.USBPRE = RCC_USBCLKSource; RCC.CFGR0.B.USBPRE = RCC_USBCLKSource;
} }
static void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState) {
if (NewState != DISABLE) {
RCC.AHBPCENR.R |= RCC_AHBPeriph;
} else {
RCC.AHBPCENR.R &= ~RCC_AHBPeriph;
}
}
/********************************************************************* /*********************************************************************
* @fn USBFS_RCC_Init * @fn USBFS_RCC_Init
* *
@ -34,14 +31,14 @@ static void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewSta
* @return none * @return none
*/ */
static void USBFS_RCC_Init( void ) { static void USBFS_RCC_Init( void ) {
if( SystemCoreClock == 144000000 ) { if( SystemCoreClock == 144'000'000 ) {
RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div3 ); RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div3 );
} else if( SystemCoreClock == 96000000 ) { } else if( SystemCoreClock == 96'000'000 ) {
RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div2 ); RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div2 );
} else if( SystemCoreClock == 48000000 ) { } else if( SystemCoreClock == 48'000'000 ) {
RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div1 ); RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div1 );
} }
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_USBFS, ENABLE ); RCC.AHBPCENR.B.OTG_EN = SET;
} }
/********************************************************************* /*********************************************************************
* @fn USBFS_Device_Endp_Init * @fn USBFS_Device_Endp_Init
@ -103,7 +100,8 @@ void cdc_class::USBFS_Device_Init( bool sta ) {
dtr << true; dtr << true;
} }
cdc_class::cdc_class() noexcept : BaseLayer(), dtr (GPIOA, 0), TxRing(), Ready(false) { cdc_class::cdc_class() noexcept : BaseLayer(),
CtrlIface(nullptr), dtr (GPIOA, 0), TxRing(), Ready(false), LineCoding() {
pInstance = this; pInstance = this;
USBFS_DevConfig = 0; USBFS_DevConfig = 0;
USBFS_DevAddr = 0; USBFS_DevAddr = 0;
@ -116,7 +114,7 @@ void cdc_class::init() {
USBFS_Device_Init( true ); USBFS_Device_Init( true );
while (!USBFS_DevEnumStatus) delay_us(10'000); while (!USBFS_DevEnumStatus) delay_us(10'000);
} }
__always_inline void cdc_class::InTokenHandler(const uint8_t intst) { [[gnu::__always_inline__]] void cdc_class::InTokenHandler(const uint8_t intst) {
switch ( intst & ( USBFS_UIS_TOKEN_MASK | USBFS_UIS_ENDP_MASK ) ) { switch ( intst & ( USBFS_UIS_TOKEN_MASK | USBFS_UIS_ENDP_MASK ) ) {
/* end-point 0 data in interrupt */ /* end-point 0 data in interrupt */
case USBFS_UIS_TOKEN_IN | DEF_UEP0: case USBFS_UIS_TOKEN_IN | DEF_UEP0:
@ -164,7 +162,7 @@ __always_inline void cdc_class::InTokenHandler(const uint8_t intst) {
break; break;
} }
} }
__always_inline void cdc_class::OutTokenHandler(const uint8_t intst) { [[gnu::__always_inline__]] void cdc_class::OutTokenHandler(const uint8_t intst) {
uint16_t len; uint16_t len;
switch ( intst & ( USBFS_UIS_TOKEN_MASK | USBFS_UIS_ENDP_MASK ) ) { switch ( intst & ( USBFS_UIS_TOKEN_MASK | USBFS_UIS_ENDP_MASK ) ) {
/* end-point 0 data out interrupt */ /* end-point 0 data out interrupt */
@ -183,24 +181,8 @@ __always_inline void cdc_class::OutTokenHandler(const uint8_t intst) {
1 byte: number of stop bits (0: 1 stop bit; 1: 1.5 stop bit; 2: 2 stop bits). 1 byte: number of stop bits (0: 1 stop bit; 1: 1.5 stop bit; 2: 2 stop bits).
1 byte: number of parity bits (0: None; 1: Odd; 2: Even; 3: Mark; 4: Space). 1 byte: number of parity bits (0: None; 1: Odd; 2: Even; 3: Mark; 4: Space).
1 byte: number of data bits (5,6,7,8,16); */ 1 byte: number of data bits (5,6,7,8,16); */
/* memcpy(& LineCoding, USBFS_EP0_Buf, sizeof (LineCoding));
Uart.Com_Cfg[ 0 ] = USBFS_EP0_Buf[ 0 ]; if (CtrlIface) CtrlIface->IOCtrl(USB_USART_SET_PARAM, & LineCoding, sizeof (LineCoding));
Uart.Com_Cfg[ 1 ] = USBFS_EP0_Buf[ 1 ];
Uart.Com_Cfg[ 2 ] = USBFS_EP0_Buf[ 2 ];
Uart.Com_Cfg[ 3 ] = USBFS_EP0_Buf[ 3 ];
Uart.Com_Cfg[ 4 ] = USBFS_EP0_Buf[ 4 ];
Uart.Com_Cfg[ 5 ] = USBFS_EP0_Buf[ 5 ];
Uart.Com_Cfg[ 6 ] = USBFS_EP0_Buf[ 6 ];
Uart.Com_Cfg[ 7 ] = DEF_UARTx_RX_TIMEOUT;
baudrate = USBFS_EP0_Buf[ 0 ];
baudrate += ((uint32_t)USBFS_EP0_Buf[ 1 ] << 8 );
baudrate += ((uint32_t)USBFS_EP0_Buf[ 2 ] << 16 );
baudrate += ((uint32_t)USBFS_EP0_Buf[ 3 ] << 24 );
Uart.Com_Cfg[ 7 ] = Uart.Rx_TimeOutMax;
UART2_USB_Init( );
*/
} }
} else { } else {
/* Standard request end-point 0 Data download */ /* Standard request end-point 0 Data download */
@ -227,7 +209,12 @@ __always_inline void cdc_class::OutTokenHandler(const uint8_t intst) {
break; break;
} }
} }
void cdc_class::SetupTokenHandler() { union DtrRts {
uint16_t data;
uint8_t bytes [2];
explicit DtrRts (const uint16_t n) noexcept { data = n; }
};
[[gnu::__always_inline__]] void cdc_class::SetupTokenHandler() {
uint8_t errflag; uint8_t errflag;
uint16_t len; uint16_t len;
USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_TOG|USBFS_UEP_T_RES_NAK; USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_TOG|USBFS_UEP_T_RES_NAK;
@ -247,13 +234,16 @@ void cdc_class::SetupTokenHandler() {
switch( USBFS_SetupReqCode ) { switch( USBFS_SetupReqCode ) {
case CDC_GET_LINE_CODING: case CDC_GET_LINE_CODING:
// pUSBFS_Descr = (uint8_t *)&Uart.Com_Cfg[ 0 ]; // pUSBFS_Descr = (uint8_t *)&Uart.Com_Cfg[ 0 ];
len = 7; pUSBFS_Descr = reinterpret_cast<uint8_t*>(& LineCoding);
len = sizeof (LineCoding);
break; break;
case CDC_SET_LINE_CODING: case CDC_SET_LINE_CODING:
break; break;
/* TODO: DTR - wValue & 1 */ /* DTR - wValue & 1, RTS - wValue & 2 */
case CDC_SET_LINE_CTLSTE: { case CDC_SET_LINE_CTLSTE: {
DtrRts tmp (USBFS_SetupReqValue);
if (CtrlIface) CtrlIface->IOCtrl(USB_USART_SET_DTR_RTS, tmp.bytes, 2);
const bool b = USBFS_SetupReqValue & 1; const bool b = USBFS_SetupReqValue & 1;
Ready = b; Ready = b;
dtr << !b; dtr << !b;
@ -507,7 +497,7 @@ void cdc_class::SetupTokenHandler() {
} }
} }
__always_inline void cdc_class::TransferHandler() { [[gnu::__always_inline__]] void cdc_class::TransferHandler() {
const uint8_t intst = USBFSD->INT_ST; const uint8_t intst = USBFSD->INT_ST;
switch (intst & USBFS_UIS_TOKEN_MASK) { switch (intst & USBFS_UIS_TOKEN_MASK) {
@ -544,6 +534,7 @@ void cdc_class::cdc_irq() {
USBFSD->DEV_ADDR = 0; USBFSD->DEV_ADDR = 0;
USBFS_Device_Endp_Init( ); USBFS_Device_Endp_Init( );
//UART2_ParaInit( 1 ); //UART2_ParaInit( 1 );
if (CtrlIface) CtrlIface->IOCtrl(USB_USART_INIT, nullptr, 0);
USBFSD->INT_FG = USBFS_UIF_BUS_RST; USBFSD->INT_FG = USBFS_UIF_BUS_RST;
} else if( intflag & USBFS_UIF_SUSPEND ) { } else if( intflag & USBFS_UIF_SUSPEND ) {
USBFSD->INT_FG = USBFS_UIF_SUSPEND; USBFSD->INT_FG = USBFS_UIF_SUSPEND;

View file

@ -0,0 +1,80 @@
#ifndef CDC_CLASS_H
#define CDC_CLASS_H
#include "baselayer.h"
#include "ctrlinterface.h"
#include "gpio.h"
#include "fifo.h"
#include "system.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "usb_desc.h"
#include "ch32v20x_usb.h"
/******************************************************************************/
/* Global Define */
/* end-point number */
enum EDEF_UEPS {
DEF_UEP0 = 0, DEF_UEP1, DEF_UEP2, DEF_UEP3, DEF_UEP4, DEF_UEP5, DEF_UEP6, DEF_UEP7, MAX_UEPS
};
static constexpr uint32_t DEF_UEP_NUM = MAX_UEPS;
static_assert (DEF_UEP_NUM == 8, "Number endpoints fail");
// Tohle nechám být, je to celkem jedno
#define DEF_UEP_IN 0x80
#define DEF_UEP_OUT 0x00
#define USBFSD_UEP_RX_EN 0x08
#define USBFSD_UEP_TX_EN 0x04
#define USBFSD_UEP_BUF_MOD 0x01
/* Setup Request Packets */
#define pUSBFS_SetupReqPak ((PUSB_SETUP_REQ)USBFS_EP0_Buf)
#ifdef __cplusplus
};
#endif
/** @class cdc_class
* V postatě je to převzato z originálního balíku od wch.nc, ale ten
* je napsán dost "špagetově", interface je nesrozumitelné, takže je tam dost věcí
* přidáno odhadem.
*/
class cdc_class : public BaseLayer {
CDC_CtrlInterface * CtrlIface;
GpioClass dtr;
FIFO<char, 128> TxRing;
volatile bool Ready;
USB_CDC_LineCoding LineCoding;
const uint8_t * pUSBFS_Descr;
/* Setup Request */
volatile uint8_t USBFS_SetupReqCode;
volatile uint8_t USBFS_SetupReqType;
volatile uint16_t USBFS_SetupReqValue;
volatile uint16_t USBFS_SetupReqIndex;
volatile uint16_t USBFS_SetupReqLen;
/* USB Device Status */
volatile uint8_t USBFS_DevConfig;
volatile uint8_t USBFS_DevAddr;
volatile uint8_t USBFS_DevSleepStatus;
volatile uint8_t USBFS_DevEnumStatus;
/* Endpoint Buffer */
[[gnu::aligned(4)]] uint8_t USBFS_EP0_Buf[ DEF_USBD_UEP0_SIZE ];
[[gnu::aligned(4)]] uint8_t USBFS_EP1_Buf[ DEF_USBD_ENDP1_SIZE ];
[[gnu::aligned(4)]] uint8_t USBFS_EP2_Buf[ DEF_USBD_ENDP2_SIZE ];
[[gnu::aligned(4)]] uint8_t USBFS_EP3_Buf[ DEF_USBD_ENDP3_SIZE ];
/* USB IN Endpoint Busy Flag */
volatile uint8_t USBFS_Endp_Busy[ DEF_UEP_NUM ];
public:
explicit cdc_class () noexcept;
void attach (CDC_CtrlInterface & ctrl) { CtrlIface = & ctrl; }
void init ();
void cdc_irq ();
/// Předěláno na neblokující, data se vyměňují přes FIFO, rychlejší
uint32_t Down(const char * data, const uint32_t len) override;
protected:
void USBFS_Device_Init( bool sta );
void USBFS_Device_Endp_Init ();
void TxDataDeal ();
inline void TransferHandler ();
inline void InTokenHandler (const uint8_t intst);
inline void OutTokenHandler (const uint8_t intst);
inline void SetupTokenHandler ();
};
#endif // CDC_CLASS_H

View file

@ -2,15 +2,6 @@
#define BASELAYER_H #define BASELAYER_H
#include <stdint.h> #include <stdint.h>
#ifdef __arm__
#define debug(...)
#else // ARCH_CM0
#ifdef DEBUG
#define debug printf
#else // DEBUG
#define debug(...)
#endif // DEBUG
#endif // ARCH_CM0
/** @brief Bázová třída pro stack trochu obecnějšího komunikačního protokolu. /** @brief Bázová třída pro stack trochu obecnějšího komunikačního protokolu.
* *
* @class BaseLayer * @class BaseLayer

View file

@ -0,0 +1,29 @@
#ifndef CTRLINTERFACE_DEF_H
#define CTRLINTERFACE_DEF_H
#include <stdint.h>
enum CTRL_TYPES_DEF {
UNKNOWN_TYPE = 0,
USB_USART_SET_PARAM,
USB_USART_SET_DTR_RTS,
USB_USART_INIT,
};
struct USB_CDC_LineCoding {
uint32_t baud;
uint8_t stop, parity, data;
explicit USB_CDC_LineCoding () noexcept : baud (57600u), stop (0u), parity (0u), data (8u) {}
}__attribute__((packed));
static_assert (sizeof(USB_CDC_LineCoding) == 7, "USB_CDC_LineCoding size error");
/** @class CtrlInterface
* Abstraktní interface, které je možné podědit třeba ve třídě USART a pomocí
* jediné virtuální metody zadefinovat chování při událostech měnících parametry
* přenosu, přicházejících po USB. Fakticky místo callback funkce, nutí to
* IOCtrl() opravdu přetížit.
* Je to mimo třídu BaseLayer, protože Up třída nemusí být totožná s kontrolní.
* V cdc_class se proto musí nastavit na toto ukazatel pomocí metody attach().
* */
class CDC_CtrlInterface {
public:
virtual bool IOCtrl (const CTRL_TYPES_DEF type, const void * data, const uint32_t len) = 0;
};
#endif // CTRLINTERFACE_DEF_H

85
V203/usb/common/print.cpp Normal file
View file

@ -0,0 +1,85 @@
#include "print.h"
#define sleep()
static const char * hexStr = "0123456789ABCDEF";
static const uint16_t numLen[] = {1, 32, 1, 11, 8, 0};
Print::Print (PrintBases b) : BaseLayer () {
base = b;
}
// Výstup blokujeme podle toho, co se vrací ze spodní vrstvy
uint32_t Print::BlockDown (const char * buf, uint32_t len) {
uint32_t n, ofs = 0, req = len;
for (;;) {
// spodní vrstva může vrátit i nulu, pokud je FIFO plné
n = BaseLayer::Down (buf + ofs, req);
ofs += n; // Posuneme ukazatel
req -= n; // Zmenšíme další požadavek
if (!req) break;
sleep(); // A klidně můžeme spát
}
return ofs;
}
Print& Print::operator<< (const char * str) {
uint32_t i = 0;
while (str[i++]); // strlen
BlockDown (str, --i);
return *this;
}
Print& Print::operator<< (const int num) {
uint32_t i = BUFLEN;
if (base == DEC) {
unsigned int u;
if (num < 0) u = -num;
else u = num;
do {
// Knihovní div() je nevhodné - dělí 2x.
// Přímočaré a funkční řešení
uint32_t rem;
rem = u % (unsigned) DEC; // 1.dělení
u = u / (unsigned) DEC; // 2.dělení
buf [--i] = hexStr [rem];
} while (u);
if (num < 0) buf [--i] = '-';
} else {
uint32_t m = (1U << (uint32_t) base) - 1U;
uint32_t l = (uint32_t) numLen [(int) base];
uint32_t u = (uint32_t) num;
for (unsigned n=0; n<l; n++) {
buf [--i] = hexStr [u & m];
u >>= (unsigned) base;
}
if (base == BIN) buf [--i] = 'b';
if (base == HEX) buf [--i] = 'x';
buf [--i] = '0';
}
BlockDown (buf+i, BUFLEN-i);
return *this;
}
Print& Print::operator<< (const PrintBases num) {
base = num;
return *this;
}
void Print::out (const void * p, uint32_t l) {
const unsigned char* q = (const unsigned char*) p;
unsigned char uc;
uint32_t k, n = 0;
for (uint32_t i=0; i<l; i++) {
uc = q[i];
buf[n++] = '<';
k = uc >> 4;
buf[n++] = hexStr [k];
k = uc & 0x0f;
buf[n++] = hexStr [k];
buf[n++] = '>';
}
buf[n++] = '\r';
buf[n++] = '\n';
BlockDown (buf, n);
}

73
V203/usb/common/print.h Normal file
View file

@ -0,0 +1,73 @@
#ifndef PRINT_H
#define PRINT_H
#include "baselayer.h"
#define EOL "\r\n"
#define BUFLEN 64
/**
* @file
* @brief Něco jako ostream.
*
*/
/// Základy pro zobrazení čísla.
enum PrintBases {
BIN=1, OCT=3, DEC=10, HEX=4
};
/**
* @class Print
* @brief Třída pro výpisy do Down().
*
*
* V main pak přibude jen definice instance této třídy
* @code
static Print print;
* @endcode
* a ukázka, jak se s tím pracuje:
* @snippet main.cpp Main print example
* Nic na tom není - operátor << přetížení pro string, číslo a volbu formátu čísla (enum PrintBases).
* Výstup je pak do bufferu a aby nám to "neutíkalo", tedy aby se vypsalo vše,
* zavedeme blokování, vycházející z toho, že spodní třída vrátí jen počet bytů,
* které skutečně odeslala. Při čekání spí, takže nepoužívat v přerušení.
* @snippet src/print.cpp Block example
* Toto blokování pak není použito ve vrchních třídách stacku,
* blokovaná metoda je BlockDown(). Pokud bychom použili přímo Down(), blokování by pak
* používaly všechny vrstvy nad tím. A protože mohou Down() používat v přerušení, byl by problém.
*
* Metody pro výpisy jsou sice dost zjednodušené, ale zase to nezabere
* moc místa - pro ladění se to použít . Délka vypisovaného stringu není omezena
* délkou použitého buferu.
*
*/
class Print : public BaseLayer {
public:
/// Konstruktor @param b Default decimální výpisy.
Print (PrintBases b = DEC);
/// Blokování výstupu
/// @param buf Ukazatel na data
/// @param len Délka přenášených dat
/// @return Počet přenesených bytů (rovno len)
uint32_t BlockDown (const char * buf, uint32_t len);
/// Výstup řetězce bytů
/// @param str Ukazatel na řetězec
/// @return Odkaz na tuto třídu kvůli řetězení.
Print & operator << (const char * str);
/// Výstup celého čísla podle base
/// @param num Číslo
/// @return Odkaz na tuto třídu kvůli řetězení.
Print & operator << (const int num);
/// Změna základu pro výstup čísla
/// @param num enum PrintBases
/// @return Odkaz na tuto třídu kvůli řetězení.
Print & operator << (const PrintBases num);
void out (const void* p, uint32_t l);
private:
PrintBases base; //!< Základ pro výstup čísla.
char buf[BUFLEN]; //!< Buffer pro výstup čísla.
};
#endif // PRINT_H