Compare commits
2 commits
c1cf18d047
...
b345a72511
Author | SHA1 | Date | |
---|---|---|---|
|
b345a72511 | ||
|
34e58e1b2b |
22 changed files with 312 additions and 155 deletions
|
@ -4,7 +4,7 @@ TOOL ?= gcc
|
|||
|
||||
PRJ = example
|
||||
|
||||
VPATH = . ./$(TARGET)
|
||||
VPATH = . ./$(TARGET) ./common
|
||||
BLD = ./build/
|
||||
DFLAGS = -d
|
||||
LFLAGS = -g
|
||||
|
@ -12,7 +12,7 @@ LDLIBS =
|
|||
BFLAGS = --strip-unneeded
|
||||
|
||||
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
|
||||
|
||||
# zdrojaky
|
||||
|
|
1
V203/usb/cdc/ch32v203
Symbolic link
1
V203/usb/cdc/ch32v203
Symbolic link
|
@ -0,0 +1 @@
|
|||
../ch32v203/
|
|
@ -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
1
V203/usb/cdc/common
Symbolic link
|
@ -0,0 +1 @@
|
|||
../common/
|
|
@ -1,31 +1,28 @@
|
|||
#include "cdc_class.h"
|
||||
#include "system.h"
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
/* Only one instance of this class ! */
|
||||
static cdc_class * pInstance = nullptr;
|
||||
/* Interrupt Service Routine Declaration*/
|
||||
extern "C" void USBFS_IRQHandler(void) __attribute__((interrupt));
|
||||
extern "C" {
|
||||
/* 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 () {
|
||||
if (pInstance) pInstance->cdc_irq();
|
||||
}
|
||||
|
||||
/* USB_Device_clock_source */
|
||||
#define RCC_USBCLKSource_PLLCLK_Div1 ((uint8_t)0x00)
|
||||
#define RCC_USBCLKSource_PLLCLK_Div2 ((uint8_t)0x01)
|
||||
#define RCC_USBCLKSource_PLLCLK_Div3 ((uint8_t)0x02)
|
||||
#define RCC_AHBPeriph_USBFS ((uint32_t)0x00001000)
|
||||
#define RCC_AHBPeriph_OTG_FS RCC_AHBPeriph_USBFS
|
||||
enum FunctionalState {DISABLE = 0, ENABLE};
|
||||
enum RCC_USB_CLK_SRC : uint32_t {
|
||||
RCC_USBCLKSource_PLLCLK_Div1 = 0u,
|
||||
RCC_USBCLKSource_PLLCLK_Div2,
|
||||
RCC_USBCLKSource_PLLCLK_Div3,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
*
|
||||
|
@ -34,14 +31,14 @@ static void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewSta
|
|||
* @return none
|
||||
*/
|
||||
static void USBFS_RCC_Init( void ) {
|
||||
if( SystemCoreClock == 144000000 ) {
|
||||
if( SystemCoreClock == 144'000'000 ) {
|
||||
RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div3 );
|
||||
} else if( SystemCoreClock == 96000000 ) {
|
||||
} else if( SystemCoreClock == 96'000'000 ) {
|
||||
RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div2 );
|
||||
} else if( SystemCoreClock == 48000000 ) {
|
||||
} else if( SystemCoreClock == 48'000'000 ) {
|
||||
RCC_USBCLKConfig( RCC_USBCLKSource_PLLCLK_Div1 );
|
||||
}
|
||||
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_USBFS, ENABLE );
|
||||
RCC.AHBPCENR.B.OTG_EN = SET;
|
||||
}
|
||||
/*********************************************************************
|
||||
* @fn USBFS_Device_Endp_Init
|
||||
|
@ -103,7 +100,8 @@ void cdc_class::USBFS_Device_Init( bool sta ) {
|
|||
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;
|
||||
USBFS_DevConfig = 0;
|
||||
USBFS_DevAddr = 0;
|
||||
|
@ -116,7 +114,7 @@ void cdc_class::init() {
|
|||
USBFS_Device_Init( true );
|
||||
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 ) ) {
|
||||
/* end-point 0 data in interrupt */
|
||||
case USBFS_UIS_TOKEN_IN | DEF_UEP0:
|
||||
|
@ -164,7 +162,7 @@ __always_inline void cdc_class::InTokenHandler(const uint8_t intst) {
|
|||
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;
|
||||
switch ( intst & ( USBFS_UIS_TOKEN_MASK | USBFS_UIS_ENDP_MASK ) ) {
|
||||
/* 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 parity bits (0: None; 1: Odd; 2: Even; 3: Mark; 4: Space).
|
||||
1 byte: number of data bits (5,6,7,8,16); */
|
||||
/*
|
||||
Uart.Com_Cfg[ 0 ] = USBFS_EP0_Buf[ 0 ];
|
||||
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( );
|
||||
*/
|
||||
memcpy(& LineCoding, USBFS_EP0_Buf, sizeof (LineCoding));
|
||||
if (CtrlIface) CtrlIface->IOCtrl(USB_USART_SET_PARAM, & LineCoding, sizeof (LineCoding));
|
||||
}
|
||||
} else {
|
||||
/* Standard request end-point 0 Data download */
|
||||
|
@ -227,7 +209,12 @@ __always_inline void cdc_class::OutTokenHandler(const uint8_t intst) {
|
|||
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;
|
||||
uint16_t len;
|
||||
USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_TOG|USBFS_UEP_T_RES_NAK;
|
||||
|
@ -247,13 +234,16 @@ void cdc_class::SetupTokenHandler() {
|
|||
switch( USBFS_SetupReqCode ) {
|
||||
case CDC_GET_LINE_CODING:
|
||||
// pUSBFS_Descr = (uint8_t *)&Uart.Com_Cfg[ 0 ];
|
||||
len = 7;
|
||||
pUSBFS_Descr = reinterpret_cast<uint8_t*>(& LineCoding);
|
||||
len = sizeof (LineCoding);
|
||||
break;
|
||||
|
||||
case CDC_SET_LINE_CODING:
|
||||
break;
|
||||
/* TODO: DTR - wValue & 1 */
|
||||
/* DTR - wValue & 1, RTS - wValue & 2 */
|
||||
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;
|
||||
Ready = 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;
|
||||
|
||||
switch (intst & USBFS_UIS_TOKEN_MASK) {
|
||||
|
@ -544,6 +534,7 @@ void cdc_class::cdc_irq() {
|
|||
USBFSD->DEV_ADDR = 0;
|
||||
USBFS_Device_Endp_Init( );
|
||||
//UART2_ParaInit( 1 );
|
||||
if (CtrlIface) CtrlIface->IOCtrl(USB_USART_INIT, nullptr, 0);
|
||||
USBFSD->INT_FG = USBFS_UIF_BUS_RST;
|
||||
} else if( intflag & USBFS_UIF_SUSPEND ) {
|
||||
USBFSD->INT_FG = USBFS_UIF_SUSPEND;
|
80
V203/usb/ch32v203/cdc_class.h
Normal file
80
V203/usb/ch32v203/cdc_class.h
Normal 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
|
|
@ -2,15 +2,6 @@
|
|||
#define BASELAYER_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.
|
||||
*
|
||||
* @class BaseLayer
|
29
V203/usb/common/ctrlinterface.h
Normal file
29
V203/usb/common/ctrlinterface.h
Normal 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
85
V203/usb/common/print.cpp
Normal 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
73
V203/usb/common/print.h
Normal 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 << má 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á. 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
|
Loading…
Reference in a new issue