├── tests ├── test_src │ ├── usb │ │ ├── USB_PCD.h │ │ ├── msc │ │ │ ├── USB_Storage.h │ │ │ ├── USB_MSC.h │ │ │ ├── SCSI.h │ │ │ ├── USB_MSC.c │ │ │ └── SCSI.c │ │ ├── USB_CTL.h │ │ ├── USB_EP.h │ │ ├── cdc │ │ │ ├── USB_CDC.h │ │ │ └── USB_CDC.c │ │ ├── USB_Class.h │ │ ├── USB_PCD.c │ │ ├── USB_Defs.h │ │ ├── USB_CTL.c │ │ └── USB_EP.c │ └── test.h └── test.py ├── LICENSE.txt ├── .gitignore ├── README.md └── preprocessor.py /tests/test_src/usb/USB_PCD.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_PCD_H 2 | #define USB_PCD_H 3 | 4 | #include "STM32X.h" 5 | 6 | 7 | /* 8 | * PUBLIC DEFINITIONS 9 | */ 10 | 11 | /* 12 | * PUBLIC TYPES 13 | */ 14 | 15 | /* 16 | * PUBLIC FUNCTIONS 17 | */ 18 | 19 | void USB_PCD_Init(void); 20 | void USB_PCD_Start(void); 21 | void USB_PCD_Stop(void); 22 | void USB_PCD_Deinit(void); 23 | void USB_PCD_SetAddress(uint8_t address); 24 | 25 | /* 26 | * EXTERN DECLARATIONS 27 | */ 28 | 29 | #endif //USB_PCD_H 30 | -------------------------------------------------------------------------------- /tests/test_src/usb/msc/USB_Storage.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_STORAGE_H 2 | #define USB_STORAGE_H 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | * PUBLIC DEFINITIONS 9 | */ 10 | 11 | #define USB_MSC_BLOCK_SIZE 512 12 | 13 | /* 14 | * PUBLIC TYPES 15 | */ 16 | 17 | typedef struct { 18 | bool (*open)(uint32_t * blk_count); 19 | bool (*read)(uint8_t * bfr, uint32_t blk_addr, uint16_t blk_count); 20 | bool (*write)(const uint8_t * bfr, uint32_t blk_addr, uint16_t blk_count); 21 | }USB_Storage_t; 22 | 23 | 24 | 25 | #endif //USB_STORAGE_H 26 | -------------------------------------------------------------------------------- /tests/test_src/test.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_H 2 | #define TEST_H 3 | 4 | /* 5 | * PUBLIC DEFINITIONS 6 | */ 7 | 8 | #define MACRO_CONST 0x1 9 | 10 | #ifdef MACRO_CONST 11 | #define MACRO_A(a,b) (a + b) 12 | #define MACRO_B(a) (a + MACRO_CONST) 13 | #define MACRO_C(a,b) (MACRO_A(a, 1) + MACRO_B(b)) 14 | #define MACRO_D(v) (v & (512 - 1)) 15 | #else 16 | #error "This clause should not be reached" 17 | #endif 18 | 19 | /* 20 | * PUBLIC TYPES 21 | */ 22 | 23 | /* 24 | * PUBLIC FUNCTIONS 25 | */ 26 | 27 | /* 28 | * EXTERN DECLARATIONS 29 | */ 30 | 31 | #endif //TEST_H 32 | -------------------------------------------------------------------------------- /tests/test_src/usb/USB_CTL.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_CTL_H 2 | #define USB_CTL_H 3 | 4 | #include "STM32X.h" 5 | 6 | /* 7 | * PUBLIC DEFINITIONS 8 | */ 9 | 10 | /* 11 | * PUBLIC TYPES 12 | */ 13 | 14 | /* 15 | * PUBLIC FUNCTIONS 16 | */ 17 | 18 | void USB_CTL_Init(void); 19 | void USB_CTL_Deinit(void); 20 | 21 | // Called by status requests on EP0 22 | void USB_CTL_HandleSetup(uint8_t * data); 23 | 24 | // Required by classes to reply to EP0 requests 25 | void USB_CTL_Send(uint8_t * data, uint16_t size); 26 | void USB_CTL_Receive(uint8_t * data, uint16_t size); 27 | 28 | /* 29 | * EXTERN DECLARATIONS 30 | */ 31 | 32 | #endif //USB_CTL_H 33 | -------------------------------------------------------------------------------- /tests/test_src/usb/msc/USB_MSC.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_MSC_H 2 | #define USB_MSC_H 3 | 4 | #include "STM32X.h" 5 | #include "../USB_Defs.h" 6 | #include "USB_Storage.h" 7 | 8 | /* 9 | * FUNCTIONAL TESTING 10 | * STM32L0: Y 11 | * STM32F0: N 12 | */ 13 | 14 | /* 15 | * PUBLIC DEFINITIONS 16 | */ 17 | 18 | #define USB_MSC_INTERFACES 1 19 | #define USB_MSC_ENDPOINTS 2 20 | 21 | #define USB_MSC_CONFIG_DESC_SIZE 32 22 | #define USB_MSC_CONFIG_DESC cUSB_MSC_ConfigDescriptor 23 | 24 | #define MSC_IN_EP 0x81 25 | #define MSC_OUT_EP 0x01 26 | 27 | /* 28 | * PUBLIC TYPES 29 | */ 30 | 31 | /* 32 | * PUBLIC FUNCTIONS 33 | */ 34 | 35 | // Callbacks for USB_CTL. 36 | // These should be referenced in USB_Class.h 37 | void USB_MSC_Init(uint8_t config); 38 | void USB_MSC_Deinit(void); 39 | void USB_MSC_Setup(USB_SetupRequest_t * req); 40 | 41 | // Interface to user 42 | void USB_MSC_Mount(const USB_Storage_t * storage); 43 | 44 | /* 45 | * EXTERN DECLARATIONS 46 | */ 47 | 48 | extern const uint8_t cUSB_MSC_ConfigDescriptor[USB_MSC_CONFIG_DESC_SIZE]; 49 | 50 | 51 | #endif //USB_MSC_H 52 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Lambosaurus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_src/usb/USB_EP.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_EP_H 2 | #define USB_EP_H 3 | 4 | #include "STM32X.h" 5 | 6 | /* 7 | * PUBLIC DEFINITIONS 8 | */ 9 | 10 | /* 11 | * PUBLIC TYPES 12 | */ 13 | 14 | typedef enum { 15 | USB_EP_TYPE_NONE, 16 | USB_EP_TYPE_CTRL, 17 | USB_EP_TYPE_BULK, 18 | USB_EP_TYPE_INTR, 19 | USB_EP_TYPE_ISOC, 20 | } USB_EP_Type_t; 21 | 22 | typedef void (*USB_EP_Callback_t)(uint32_t count); 23 | 24 | /* 25 | * PUBLIC FUNCTIONS 26 | */ 27 | 28 | void USB_EP_Init(void); 29 | void USB_EP_Deinit(void); 30 | void USB_EP_Reset(void); 31 | 32 | void USB_EP_Open(uint8_t endpoint, uint8_t type, uint16_t size, USB_EP_Callback_t callback); 33 | void USB_EP_Close(uint8_t endpoint); 34 | bool USB_EP_IsOpen(uint8_t endpoint); 35 | void USB_EP_Read(uint8_t endpoint, uint8_t *data, uint32_t count); 36 | void USB_EP_Write(uint8_t endpoint, const uint8_t * data, uint32_t count); 37 | void USB_EP_WriteZLP(uint8_t endpoint); 38 | void USB_EP_Stall(uint8_t endpoint); 39 | void USB_EP_Destall(uint8_t endpoint); 40 | bool USB_EP_IsStalled(uint8_t endpoint); 41 | 42 | void USB_EP_IRQHandler(void); 43 | 44 | /* 45 | * EXTERN DECLARATIONS 46 | */ 47 | 48 | #endif //USB_EP_H 49 | -------------------------------------------------------------------------------- /tests/test_src/usb/cdc/USB_CDC.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_CDC_H 2 | #define USB_CDC_H 3 | 4 | #include "STM32X.h" 5 | #include "../USB_Defs.h" 6 | 7 | /* 8 | * FUNCTIONAL TESTING 9 | * STM32L0: Y 10 | * STM32F0: N 11 | */ 12 | 13 | /* 14 | * PUBLIC DEFINITIONS 15 | */ 16 | 17 | #define USB_CDC_INTERFACES 2 18 | #define USB_CDC_ENDPOINTS 3 19 | 20 | #define USB_CDC_CLASSID 0x02 21 | #define USB_CDC_SUBCLASSID 0x02 22 | #define USB_CDC_PROTOCOLID 0x00 23 | 24 | #define USB_CDC_CONFIG_DESC_SIZE 67 25 | #define USB_CDC_CONFIG_DESC cUSB_CDC_ConfigDescriptor 26 | 27 | /* 28 | * PUBLIC TYPES 29 | */ 30 | 31 | /* 32 | * PUBLIC FUNCTIONS 33 | */ 34 | 35 | // Callbacks for USB_CTL. 36 | // These should be referenced in USB_Class.h 37 | void USB_CDC_Init(uint8_t config); 38 | void USB_CDC_Deinit(void); 39 | void USB_CDC_CtlRxReady(void); 40 | void USB_CDC_Setup(USB_SetupRequest_t * req); 41 | 42 | // Interface to user 43 | uint32_t USB_CDC_ReadReady(void); 44 | uint32_t USB_CDC_Read(uint8_t * data, uint32_t count); 45 | void USB_CDC_Write(const uint8_t * data, uint32_t count); 46 | 47 | /* 48 | * EXTERN DECLARATIONS 49 | */ 50 | 51 | extern const uint8_t cUSB_CDC_ConfigDescriptor[USB_CDC_CONFIG_DESC_SIZE]; 52 | 53 | 54 | #endif //USB_CDC_H 55 | -------------------------------------------------------------------------------- /tests/test_src/usb/USB_Class.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_CLASS_H 2 | #define USB_CLASS_H 3 | 4 | #include "STM32X.h" 5 | 6 | /* 7 | * PUBLIC DEFINITIONS 8 | */ 9 | 10 | #if defined(USB_CLASS_CDC) 11 | #include "cdc/USB_CDC.h" 12 | 13 | #define USB_CLASS_CLASSID USB_CDC_CLASSID 14 | #define USB_CLASS_SUBCLASSID USB_CDC_SUBCLASSID 15 | #define USB_CLASS_PROTOCOLID USB_CDC_PROTOCOLID 16 | #define USB_CLASS_DEVICE_DESCRIPTOR USB_CDC_CONFIG_DESC 17 | 18 | 19 | #define USB_CLASS_INIT(config) USB_CDC_Init(config) 20 | #define USB_CLASS_DEINIT() USB_CDC_Deinit() 21 | #define USB_CLASS_SETUP(request) USB_CDC_Setup(request) 22 | #define USB_CLASS_CTL_RXREADY() USB_CDC_CtlRxReady() 23 | //#define USB_CLASS_CTL_TXDONE 24 | 25 | #define USB_ENDPOINTS USB_CDC_ENDPOINTS 26 | #define USB_INTERFACES USB_CDC_INTERFACES 27 | 28 | #elif defined(USB_CLASS_MSC) 29 | #include "msc/USB_MSC.h" 30 | 31 | #define USB_CLASS_DEVICE_DESCRIPTOR USB_MSC_CONFIG_DESC 32 | 33 | #define USB_CLASS_INIT(config) USB_MSC_Init(config) 34 | #define USB_CLASS_DEINIT() USB_MSC_Deinit() 35 | #define USB_CLASS_SETUP(request) USB_MSC_Setup(request) 36 | 37 | #define USB_ENDPOINTS USB_MSC_ENDPOINTS 38 | #define USB_INTERFACES USB_MSC_INTERFACES 39 | 40 | #else 41 | #error "No USB Class defined" 42 | #endif 43 | 44 | /* 45 | * PUBLIC TYPES 46 | */ 47 | 48 | /* 49 | * PUBLIC FUNCTIONS 50 | */ 51 | 52 | /* 53 | * EXTERN DECLARATIONS 54 | */ 55 | 56 | #endif //USB_CLASS_H 57 | -------------------------------------------------------------------------------- /tests/test_src/usb/msc/SCSI.h: -------------------------------------------------------------------------------- 1 | #ifndef SCSI_H 2 | #define SCSI_H 3 | 4 | #include 5 | #include 6 | #include "USB_Storage.h" 7 | 8 | /* 9 | * PUBLIC DEFINITIONS 10 | */ 11 | 12 | #define SCSI_BLOCK_SIZE 512 13 | #define SCSI_SENSE_DEPTH 4 14 | 15 | /* 16 | * PUBLIC TYPES 17 | */ 18 | 19 | typedef struct 20 | { 21 | char Skey; 22 | uint8_t ASC; 23 | } SCSI_Sense_t; 24 | 25 | typedef struct 26 | { 27 | uint32_t dSignature; 28 | uint32_t dTag; 29 | uint32_t dDataLength; 30 | uint8_t bmFlags; 31 | uint8_t bLUN; 32 | uint8_t bCBLength; 33 | uint8_t CB[16]; 34 | uint8_t ReservedForAlign; 35 | } SCSI_CBW_t; 36 | 37 | typedef struct 38 | { 39 | uint32_t dSignature; 40 | uint32_t dTag; 41 | uint32_t dDataResidue; 42 | uint8_t bStatus; 43 | uint8_t ReservedForAlign[3]; 44 | } SCSI_CSW_t; 45 | 46 | typedef struct { 47 | const USB_Storage_t * storage; 48 | 49 | uint32_t block_count; 50 | uint32_t block_addr; 51 | uint32_t block_len; 52 | 53 | struct { 54 | SCSI_Sense_t stack[SCSI_SENSE_DEPTH]; 55 | uint8_t head; 56 | uint8_t tail; 57 | } sense; 58 | 59 | uint8_t bfr[SCSI_BLOCK_SIZE]; 60 | uint16_t data_len; 61 | } SCSI_t; 62 | 63 | typedef enum { 64 | SCSI_State_Error = -1, 65 | SCSI_State_Ok = 0, 66 | SCSI_State_SendData, 67 | SCSI_State_DataOut, 68 | SCSI_State_DataIn, 69 | SCSI_State_LastDataIn, 70 | } SCSI_State_t; 71 | 72 | /* 73 | * PUBLIC FUNCTIONS 74 | */ 75 | 76 | SCSI_State_t SCSI_Init(SCSI_t * scsi, const USB_Storage_t * storage); 77 | SCSI_State_t SCSI_ProcessCmd(SCSI_t * scsi, SCSI_CBW_t * cbw); 78 | SCSI_State_t SCSI_ResumeCmd(SCSI_t * scsi, SCSI_State_t state); 79 | 80 | #endif // SCSI_H 81 | 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # py-c-preprocessor 2 | A preprocessor for C files written in python 3 | 4 | # What? 5 | This is a preprocessor for C files written in python. It consumes C source and headers and generates outputs that are useful for code analysis and generation, such as: 6 | * Preprocessed C source 7 | * List of defined macros 8 | * Helpers for expanding and evaluating expresions 9 | 10 | File can be passed in by paths, and headers included by #include directives, or passed in directly. 11 | 12 | # Why? 13 | I wanted to be able to parse C headers programmatically in python, and use found definitions for code generation. This originally started as just a way to gather all defined macros, but it turns out you need to do most other tasks to do that correctly in a realistic code base. All other features are an eventual result of this requirement. 14 | 15 | I could have solved this by just using gcc -E, but I had some reasons not to: 16 | * Didnt want to write to the file system 17 | * Didnt want to introduce a compiler as a dependancy 18 | * Having all expressions in python makes code generation/examination very tidy 19 | 20 | # How? 21 | Mostly regex. Github Copilot was actually much more useful that expected. 22 | 23 | # Usage 24 | 25 | ```python 26 | from preprocessor import Preprocessor 27 | p = Preprocessor() 28 | 29 | # Include paths for headers can be specified 30 | p.add_include_path('/path/to/headers') 31 | 32 | # You can ignore missing includes to skip system included headers, such as stdio.h 33 | p.ignore_missing_includes = True 34 | 35 | # Macros can be defined before parsing 36 | p.define('MACRO_A', '1') 37 | p.define('MACRO_B', '(x + y / z)', ['x', 'y', 'z']) 38 | 39 | # Source or headers can be included 40 | p.include('/path/to/file.c') 41 | 42 | # Multiple files can be included 43 | # Source can also be supplied in place 44 | p.include('/dummy/path.c', """ 45 | #ifdef MACRO_A 46 | #define MACRO_C(x,y,z) MACRO_B(x,y,z) 47 | #else 48 | #define MACRO_C(x,y,z) (1) 49 | #endif 50 | 51 | int main() 52 | { 53 | return MACRO_C(1,2,3); 54 | } 55 | """ 56 | ) 57 | 58 | # once the required source is parsed, expressions can be expanded 59 | print(p.expand('MACRO_A + MACRO_C(1,2,3)')) # returns "1 + (1 + 2 / 3)" 60 | 61 | # expressions can also be evaluated if they resolve to to primitive expressions 62 | print(p.evaluate('MACRO_A + MACRO_C(1,2,3)')) # returns 2 63 | 64 | # The preprocessed source can then be expanded 65 | print(p.source()) 66 | # prints: 67 | # int main() 68 | # { 69 | # return 1 + 2 / 3; 70 | # } 71 | ``` 72 | -------------------------------------------------------------------------------- /tests/test_src/usb/USB_PCD.c: -------------------------------------------------------------------------------- 1 | 2 | #include "USB_PCD.h" 3 | 4 | #ifdef USB_ENABLE 5 | #include "USB_EP.h" 6 | #include "USB_CTL.h" 7 | #include "USB_CLASS.h" 8 | 9 | /* 10 | * PRIVATE DEFINITIONS 11 | */ 12 | 13 | #define USB_GET_IRQ() (USB->ISTR) 14 | #define USB_CLR_IRQ(flag) (USB->ISTR &= ~flag) 15 | 16 | /* 17 | * PRIVATE TYPES 18 | */ 19 | 20 | /* 21 | * PRIVATE PROTOTYPES 22 | */ 23 | 24 | static void USB_PCD_Reset(void); 25 | 26 | /* 27 | * PRIVATE VARIABLES 28 | */ 29 | 30 | #ifdef USB_USE_LPM 31 | static struct { 32 | uint8_t lowPowerMode; 33 | } gPCD; 34 | #endif 35 | 36 | /* 37 | * PUBLIC FUNCTIONS 38 | */ 39 | 40 | void USB_PCD_Init(void) 41 | { 42 | USB->CNTR = USB_CNTR_FRES; // Issue reset 43 | USB->CNTR = 0; 44 | USB->ISTR = 0; 45 | USB->BTABLE = BTABLE_ADDRESS; 46 | 47 | USB_EP_Init(); 48 | 49 | #ifdef USB_USE_LPM 50 | gPCD.lowPowerMode = LPM_L0; 51 | USB->LPMCSR |= USB_LPMCSR_LMPEN; 52 | USB->LPMCSR |= USB_LPMCSR_LPMACK; 53 | #endif 54 | } 55 | 56 | void USB_PCD_Start(void) 57 | { 58 | // Enable interrupt sources 59 | USB->CNTR = USB_CNTR_CTRM | USB_CNTR_RESETM 60 | #ifdef USB_USE_LPM 61 | | USB_CNTR_WKUPM | USB_CNTR_SUSPM | USB_CNTR_L1REQM 62 | #endif 63 | // | USB_CNTR_SOFM | USB_CNTR_ESOFM | USB_CNTR_ERRM 64 | // | USB_CNTR_RESUME remote wakeup mode? 65 | ; 66 | 67 | USB->BCDR |= USB_BCDR_DPPU; // Enable DP pullups 68 | } 69 | 70 | void USB_PCD_Stop(void) 71 | { 72 | // disable all interrupts and force USB reset 73 | USB->CNTR = USB_CNTR_FRES; 74 | USB->ISTR = 0U; 75 | // switch-off device 76 | USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; 77 | // Disable DP pullups 78 | USB->BCDR &= ~USB_BCDR_DPPU; 79 | } 80 | 81 | void USB_PCD_SetAddress(uint8_t address) 82 | { 83 | USB->DADDR = address | USB_DADDR_EF; 84 | } 85 | 86 | /* 87 | * PRIVATE FUNCTIONS 88 | */ 89 | 90 | static void USB_PCD_Reset(void) 91 | { 92 | // Clear existing endpoint layouts. 93 | USB_CTL_Deinit(); 94 | USB_EP_Reset(); 95 | USB_PCD_SetAddress(0); 96 | 97 | // Reinit the CTRL EP's 98 | USB_CTL_Init(); 99 | } 100 | 101 | /* 102 | * INTERRUPT ROUTINES 103 | */ 104 | 105 | void USB_IRQHandler(void) 106 | { 107 | uint32_t istr = USB_GET_IRQ(); 108 | 109 | if (istr & USB_ISTR_CTR) 110 | { 111 | USB_EP_IRQHandler(); 112 | } 113 | else if (istr & USB_ISTR_RESET) 114 | { 115 | USB_CLR_IRQ(USB_ISTR_RESET); 116 | USB_PCD_Reset(); 117 | } 118 | else if (istr & USB_ISTR_PMAOVR) 119 | { 120 | USB_CLR_IRQ(USB_ISTR_PMAOVR); 121 | } 122 | #ifdef USB_USE_LPM 123 | else if (istr & USB_ISTR_SUSP) 124 | { 125 | // Force low-power mode in the peripheral 126 | USB->CNTR |= USB_CNTR_FSUSP; 127 | // clear of the ISTR bit must be done after setting of CNTR_FSUSP 128 | USB_CLR_IRQ(USB_ISTR_SUSP); 129 | USB->CNTR |= USB_CNTR_LPMODE; 130 | } 131 | else if (istr & USB_ISTR_WKUP) 132 | { 133 | // Clear LP & suspend modes. 134 | USB->CNTR &= ~(USB_CNTR_LPMODE | USB_CNTR_FSUSP); 135 | gPCD.lowPowerMode = LPM_L0; 136 | USB_CLR_IRQ(USB_ISTR_WKUP); 137 | } 138 | else if (istr & USB_ISTR_L1REQ) 139 | { 140 | USB_CLR_IRQ(USB_ISTR_L1REQ); 141 | 142 | if (gPCD.lowPowerMode == LPM_L0) 143 | { 144 | // Force suspend and low-power mode before going to L1 state 145 | USB->CNTR |= USB_CNTR_LPMODE | USB_CNTR_FSUSP; 146 | gPCD.lowPowerMode = LPM_L1; 147 | hpcd->BESL = ((uint32_t)USB->LPMCSR & USB_LPMCSR_BESL) >> 2; 148 | } 149 | } 150 | #endif 151 | } 152 | 153 | #endif //USB_ENABLE 154 | -------------------------------------------------------------------------------- /tests/test_src/usb/msc/USB_MSC.c: -------------------------------------------------------------------------------- 1 | 2 | #include "USB_MSC.h" 3 | 4 | #ifdef USB_CLASS_MSC 5 | #include "../USB_EP.h" 6 | #include "../USB_CTL.h" 7 | #include "SCSI.h" 8 | 9 | #include 10 | 11 | 12 | /* 13 | * PRIVATE DEFINITIONS 14 | */ 15 | 16 | #define MSC_PACKET_SIZE USB_PACKET_SIZE 17 | 18 | #define MSC_CBW_SIGNATURE 0x43425355U 19 | #define MSC_CSW_SIGNATURE 0x53425355U 20 | #define MSC_CBW_LENGTH 31 21 | #define MSC_CSW_LENGTH 13 22 | #define MSC_MAX_DATA 256 23 | 24 | #define MSC_STATUS_NORMAL 0 25 | #define MSC_STATUS_RECOVERY 1 26 | #define MSC_STATUS_ERROR 2 27 | 28 | #define MSC_LUN_COUNT 1 29 | #define MSC_MAX_LUN (MSC_LUN_COUNT-1) 30 | 31 | #define MSC_REQ_GET_MAX_LUN 0xFE 32 | #define MSC_REQ_RESET 0xFF 33 | 34 | #define MSC_CSW_CMD_PASSED 0x00 35 | #define MSC_CSW_CMD_FAILED 0x01 36 | 37 | /* 38 | * PRIVATE TYPES 39 | */ 40 | 41 | /* 42 | * PRIVATE PROTOTYPES 43 | */ 44 | 45 | static void USB_MSC_Reset(void); 46 | static void USB_MSC_TransmitDone(uint32_t size); 47 | static void USB_MSC_Receive(uint32_t size); 48 | 49 | static void USB_MSC_HandleCBW(uint32_t size); 50 | static void USB_MSC_SendData(uint8_t *pbuf, uint16_t len); 51 | static void USB_MSC_Abort(void); 52 | static void USB_MSC_HandleTransfer(SCSI_State_t state); 53 | 54 | static void USB_MSC_SendCSW(uint8_t CSW_Status); 55 | 56 | /* 57 | * PRIVATE VARIABLES 58 | */ 59 | 60 | __ALIGNED(4) const uint8_t cUSB_MSC_ConfigDescriptor[USB_MSC_CONFIG_DESC_SIZE] = 61 | { 62 | USB_DESCR_BLOCK_CONFIGURATION( 63 | USB_MSC_CONFIG_DESC_SIZE, 64 | 0x01, // 1 interfaces available 65 | 0x01 66 | ), 67 | USB_DESCR_BLOCK_INTERFACE( 68 | 0x00, 69 | 0x02, // 2 endpoints used 70 | 0x08, // Mass Storage Class 71 | 0x06, // SCSI transparent 72 | 0x50 // Unknown protocol 73 | ), 74 | USB_DESCR_BLOCK_ENDPOINT( MSC_IN_EP, 0x02, MSC_PACKET_SIZE, 0x00 ), 75 | USB_DESCR_BLOCK_ENDPOINT( MSC_OUT_EP, 0x02, MSC_PACKET_SIZE, 0x00 ), 76 | }; 77 | 78 | static struct { 79 | SCSI_t scsi; 80 | uint8_t status; 81 | int8_t state; 82 | 83 | SCSI_CBW_t cbw; 84 | SCSI_CSW_t csw; 85 | 86 | const USB_Storage_t * storage; 87 | } gMSC; 88 | 89 | /* 90 | * PUBLIC FUNCTIONS 91 | */ 92 | 93 | void USB_MSC_Mount(const USB_Storage_t * storage) 94 | { 95 | gMSC.storage = storage; 96 | } 97 | 98 | void USB_MSC_Init(uint8_t config) 99 | { 100 | // Data endpoints 101 | USB_EP_Open(MSC_IN_EP, USB_EP_TYPE_BULK, MSC_PACKET_SIZE, USB_MSC_TransmitDone); 102 | USB_EP_Open(MSC_OUT_EP, USB_EP_TYPE_BULK, MSC_PACKET_SIZE, USB_MSC_Receive); 103 | 104 | gMSC.state = SCSI_Init(&gMSC.scsi, gMSC.storage); 105 | gMSC.status = MSC_STATUS_NORMAL; 106 | 107 | USB_EP_Read(MSC_OUT_EP, (uint8_t *)&gMSC.cbw, MSC_CBW_LENGTH); 108 | } 109 | 110 | void USB_MSC_Deinit(void) 111 | { 112 | USB_EP_Close(MSC_IN_EP); 113 | USB_EP_Close(MSC_OUT_EP); 114 | } 115 | 116 | void USB_MSC_Setup(USB_SetupRequest_t * req) 117 | { 118 | switch (req->bRequest) 119 | { 120 | case MSC_REQ_GET_MAX_LUN: 121 | if (req->wValue == 0 && req->wLength == 1 && req->bmRequest & 0x80) 122 | { 123 | uint8_t max_lun = MSC_MAX_LUN; 124 | USB_CTL_Send(&max_lun, sizeof(max_lun)); 125 | return; 126 | } 127 | break; 128 | case MSC_REQ_RESET: 129 | if (req->wValue == 0U && req->wLength == 0 && !(req->bmRequest & 0x80U)) 130 | { 131 | USB_MSC_Reset(); 132 | return; 133 | } 134 | break; 135 | } 136 | } 137 | 138 | /* 139 | * PRIVATE FUNCTIONS 140 | */ 141 | 142 | static void USB_MSC_Reset(void) 143 | { 144 | gMSC.status = MSC_STATUS_RECOVERY; 145 | USB_EP_Read(MSC_OUT_EP, (uint8_t *)&gMSC.cbw, MSC_CBW_LENGTH); 146 | } 147 | 148 | void USB_MSC_TransmitDone(uint32_t size) 149 | { 150 | switch (gMSC.state) 151 | { 152 | case SCSI_State_DataIn: 153 | case SCSI_State_SendData: 154 | case SCSI_State_LastDataIn: 155 | gMSC.state = SCSI_ResumeCmd(&gMSC.scsi, gMSC.state); 156 | USB_MSC_HandleTransfer(gMSC.state); 157 | break; 158 | } 159 | } 160 | 161 | void USB_MSC_Receive(uint32_t size) 162 | { 163 | switch (gMSC.state) 164 | { 165 | case SCSI_State_DataOut: 166 | gMSC.state = SCSI_ResumeCmd(&gMSC.scsi, gMSC.state); 167 | USB_MSC_HandleTransfer(gMSC.state); 168 | break; 169 | 170 | default: 171 | USB_MSC_HandleCBW(size); 172 | break; 173 | } 174 | } 175 | 176 | // Handle a new CBW message. 177 | static void USB_MSC_HandleCBW(uint32_t size) 178 | { 179 | gMSC.csw.dTag = gMSC.cbw.dTag; 180 | gMSC.csw.dDataResidue = gMSC.cbw.dDataLength; 181 | 182 | if ((size != MSC_CBW_LENGTH) || 183 | (gMSC.cbw.dSignature != MSC_CBW_SIGNATURE) || 184 | (gMSC.cbw.bLUN > 0) || 185 | (gMSC.cbw.bCBLength < 1) || (gMSC.cbw.bCBLength > 16)) 186 | { 187 | // ST had a SCSI_SenseCode here. Seems redundant. 188 | 189 | gMSC.state = SCSI_State_Error; 190 | gMSC.status = MSC_STATUS_ERROR; 191 | USB_MSC_Abort(); 192 | } 193 | else 194 | { 195 | gMSC.state = SCSI_ProcessCmd(&gMSC.scsi, &gMSC.cbw); 196 | USB_MSC_HandleTransfer(gMSC.state); 197 | } 198 | } 199 | 200 | // Does the IO for the SCSI state machine 201 | static void USB_MSC_HandleTransfer(SCSI_State_t state) 202 | { 203 | switch(state) 204 | { 205 | case SCSI_State_Error: 206 | USB_MSC_SendCSW(MSC_CSW_CMD_FAILED); 207 | break; 208 | case SCSI_State_Ok: 209 | USB_MSC_SendCSW(MSC_CSW_CMD_PASSED); 210 | break; 211 | case SCSI_State_SendData: 212 | USB_MSC_SendData(gMSC.scsi.bfr, gMSC.scsi.data_len); 213 | break; 214 | case SCSI_State_DataOut: 215 | USB_EP_Read(MSC_OUT_EP, gMSC.scsi.bfr, gMSC.scsi.data_len); 216 | gMSC.csw.dDataResidue -= gMSC.scsi.data_len; 217 | break; 218 | case SCSI_State_DataIn: 219 | case SCSI_State_LastDataIn: 220 | USB_EP_Write(MSC_IN_EP, gMSC.scsi.bfr, gMSC.scsi.data_len); 221 | gMSC.csw.dDataResidue -= gMSC.scsi.data_len; 222 | break; 223 | default: 224 | break; 225 | } 226 | } 227 | 228 | static void USB_MSC_SendData(uint8_t *pbuf, uint16_t len) 229 | { 230 | uint16_t length = (uint16_t)MIN(gMSC.cbw.dDataLength, len); 231 | 232 | gMSC.csw.dDataResidue -= len; 233 | gMSC.csw.bStatus = MSC_CSW_CMD_PASSED; 234 | 235 | USB_EP_Write( MSC_IN_EP, pbuf, length ); 236 | } 237 | 238 | static void USB_MSC_SendCSW(uint8_t CSW_Status) 239 | { 240 | gMSC.csw.dSignature = MSC_CSW_SIGNATURE; 241 | gMSC.csw.bStatus = CSW_Status; 242 | 243 | USB_EP_Write(MSC_IN_EP, (uint8_t *)&gMSC.csw, MSC_CSW_LENGTH); 244 | // Recieve next CBW 245 | USB_EP_Read(MSC_OUT_EP, (uint8_t *)&gMSC.cbw, MSC_CBW_LENGTH); 246 | } 247 | 248 | // Abort the current transaction 249 | static void USB_MSC_Abort(void) 250 | { 251 | if ((gMSC.cbw.bmFlags == 0) && 252 | (gMSC.cbw.dDataLength != 0) && 253 | (gMSC.status == MSC_STATUS_NORMAL)) 254 | { 255 | USB_EP_Stall(MSC_OUT_EP); 256 | } 257 | 258 | USB_EP_Stall(MSC_IN_EP); 259 | 260 | if (gMSC.status == MSC_STATUS_ERROR) 261 | { 262 | USB_EP_Read(MSC_OUT_EP, (uint8_t *)&gMSC.cbw, MSC_CBW_LENGTH); 263 | } 264 | } 265 | 266 | // Completes the USB Clear feature request. 267 | // Should be done on an interface clear feature request (I think) 268 | void MSC_BOT_CplClrFeature(uint8_t epnum) 269 | { 270 | if (gMSC.status == MSC_STATUS_ERROR) 271 | { 272 | USB_EP_Stall(MSC_IN_EP); 273 | gMSC.status = MSC_STATUS_NORMAL; 274 | } 275 | else if (((epnum & 0x80U) == 0x80U) && (gMSC.status != MSC_STATUS_RECOVERY)) 276 | { 277 | USB_MSC_SendCSW(MSC_CSW_CMD_FAILED); 278 | } 279 | } 280 | 281 | 282 | #endif //USB_CLASS_MSC 283 | 284 | -------------------------------------------------------------------------------- /tests/test_src/usb/USB_Defs.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef USB_DEFS_H 3 | #define USB_DEFS_H 4 | 5 | #include "STM32X.h" 6 | 7 | /* 8 | * PUBLIC DEFINITIONS: USB CONFIGURATION 9 | * These may be overridden in the user Board.h 10 | */ 11 | 12 | #ifndef USB_VID 13 | #define USB_VID 0x0483 14 | #endif 15 | #ifndef USB_PID 16 | #define USB_PID 0x5740 17 | #endif 18 | 19 | #define USB_LANGID 0x0409 20 | 21 | #ifndef USB_PRODUCT_STRING 22 | #define USB_PRODUCT_STRING "STM32X" 23 | #endif 24 | #ifndef USB_INTERFACE_STRING 25 | #define USB_INTERFACE_STRING "STM32X Interface" 26 | #endif 27 | #ifndef USB_CONFIGURATION_STRING 28 | #define USB_CONFIGURATION_STRING "STM32X Config" 29 | #endif 30 | #ifndef USB_MANUFACTURER_STRING 31 | #define USB_MANUFACTURER_STRING "Lambosaurus" 32 | #endif 33 | // Ensure that this is updated if string sizes are increased. 34 | #ifndef USB_MAX_STRING_SIZE 35 | #define USB_MAX_STRING_SIZE 64 36 | #endif 37 | 38 | #ifndef USB_MAX_POWER_MA 39 | #define USB_MAX_POWER_MA 100 40 | #endif 41 | 42 | #define USB_MAX_POWER (USB_MAX_POWER_MA/2) 43 | 44 | #ifndef USB_MAX_NUM_CONFIGURATION 45 | #define USB_MAX_NUM_CONFIGURATION 1 46 | #endif 47 | 48 | // USB_SELF_POWERED 49 | // TODO: handle this in device descriptor 50 | 51 | #define USB_MAX_EP0_SIZE 64 52 | 53 | #ifdef USB_SPEED_FULL 54 | #define USB_PACKET_SIZE 512 55 | #else 56 | #define USB_PACKET_SIZE 64 57 | #endif 58 | 59 | #if (BTABLE_ADDRESS != 0) 60 | #error "Btable is expected to be 0x0000" 61 | #endif 62 | 63 | /* 64 | * PUBLIC DEFINITIONS: HELPER MACROS 65 | */ 66 | 67 | #define SWAPBYTE(addr) (((uint16_t)(*(addr))) | (((uint16_t)(*((addr) + 1))) << 8)) 68 | 69 | #define LOBYTE(x) ((uint8_t)(x)) 70 | #define HIBYTE(x) ((uint8_t)((x) >> 8)) 71 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 72 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 73 | 74 | #ifndef __ALIGNED 75 | #define __ALIGNED(n) __attribute__((aligned(n))) 76 | #endif 77 | 78 | /* 79 | * PUBLIC DEFINITIONS: USB DESCRIPTOR DEFS 80 | */ 81 | 82 | #define USB_FEATURE_EP_HALT 0x00 83 | #define USB_FEATURE_REMOTE_WAKEUP 0x01 84 | #define USB_FEATURE_TEST_MODE 0x02 85 | 86 | #define USB_CONFIG_REMOTE_WAKEUP 0x02 87 | #define USB_CONFIG_SELF_POWERED 0x01 88 | 89 | 90 | #define USB_LEN_DEV_QUALIFIER_DESC 0x0A 91 | #define USB_LEN_DEV_DESC 0x12 92 | #define USB_LEN_CFG_DESC 0x09 93 | #define USB_LEN_IF_DESC 0x09 94 | #define USB_LEN_EP_DESC 0x07 95 | #define USB_LEN_OTG_DESC 0x03 96 | #define USB_LEN_LANGID_STR_DESC 0x04 97 | #define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09 98 | 99 | #define USB_IDX_LANGID_STR 0x00 100 | #define USB_IDX_MFC_STR 0x01 101 | #define USB_IDX_PRODUCT_STR 0x02 102 | #define USB_IDX_SERIAL_STR 0x03 103 | #define USB_IDX_CONFIG_STR 0x04 104 | #define USB_IDX_INTERFACE_STR 0x05 105 | 106 | #define USB_REQ_TYPE_STANDARD 0x00 107 | #define USB_REQ_TYPE_CLASS 0x20 108 | #define USB_REQ_TYPE_VENDOR 0x40 109 | #define USB_REQ_TYPE_MASK 0x60 110 | 111 | #define USB_REQ_RECIPIENT_DEVICE 0x00 112 | #define USB_REQ_RECIPIENT_INTERFACE 0x01 113 | #define USB_REQ_RECIPIENT_ENDPOINT 0x02 114 | #define USB_REQ_RECIPIENT_MASK 0x03 115 | 116 | #define USB_REQ_GET_STATUS 0x00 117 | #define USB_REQ_CLEAR_FEATURE 0x01 118 | #define USB_REQ_SET_FEATURE 0x03 119 | #define USB_REQ_SET_ADDRESS 0x05 120 | #define USB_REQ_GET_DESCRIPTOR 0x06 121 | #define USB_REQ_SET_DESCRIPTOR 0x07 122 | #define USB_REQ_GET_CONFIGURATION 0x08 123 | #define USB_REQ_SET_CONFIGURATION 0x09 124 | #define USB_REQ_GET_INTERFACE 0x0A 125 | #define USB_REQ_SET_INTERFACE 0x0B 126 | #define USB_REQ_SYNCH_FRAME 0x0C 127 | 128 | #define USB_DESC_TYPE_DEVICE 0x01 129 | #define USB_DESC_TYPE_CONFIGURATION 0x02 130 | #define USB_DESC_TYPE_STRING 0x03 131 | #define USB_DESC_TYPE_INTERFACE 0x04 132 | #define USB_DESC_TYPE_ENDPOINT 0x05 133 | #define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06 134 | #define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07 135 | #define USB_DESC_TYPE_INTERFACE_ASSOCIATION 0x0B 136 | #define USB_DESC_TYPE_BOS 0x0F 137 | 138 | 139 | /* 140 | * PUBLIC DEFINITIONS: USB DESCRIPTOR BLOCKS 141 | */ 142 | 143 | /* 144 | * Descriptor block for describing endpoints 145 | * 146 | * bLength: Endpoint descriptor size 147 | * bDescriptorType: Endpoint 148 | * bEndpointAddress 149 | * bmAttributes: (0x02 for bulk) 150 | * wMaxPacketSize: 151 | * bInterval: (0 for for Bulk transfer) 152 | */ 153 | 154 | #define USB_DESCR_BLOCK_ENDPOINT(bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval) \ 155 | 0x07, \ 156 | USB_DESC_TYPE_ENDPOINT, \ 157 | bEndpointAddress, \ 158 | bmAttributes, \ 159 | LOBYTE(wMaxPacketSize), \ 160 | HIBYTE(wMaxPacketSize), \ 161 | bInterval 162 | 163 | 164 | /* 165 | * Descriptor block for describing interfaces 166 | * 167 | * bLength: Interface descriptor size 168 | * bDescriptorType: Interface 169 | * bInterfaceNumber: Number of Interface 170 | * bAlternateSetting: Alternate setting 171 | * bNumEndpoints: 172 | * bInterfaceClass: 173 | * bInterfaceSubClass: 174 | * bInterfaceProtocol: 175 | * iInterface: (0 for no string) 176 | */ 177 | 178 | #define USB_DESCR_BLOCK_INTERFACE(bInterfaceNumber, bNumEndpoints, bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol) \ 179 | 0x09, \ 180 | USB_DESC_TYPE_INTERFACE, \ 181 | bInterfaceNumber, \ 182 | 0x00, \ 183 | bNumEndpoints, \ 184 | bInterfaceClass, \ 185 | bInterfaceSubClass, \ 186 | bInterfaceProtocol, \ 187 | 0x00 188 | 189 | /* 190 | * Descriptor block for describing configurations 191 | * 192 | * bLength: Configuration descriptor size 193 | * bDescriptorType: Configuration 194 | * wTotalLength: Total number of bytes in the configuration 195 | * bNumInterfaces: 196 | * bConfigurationValue: 197 | * iConfiguration: (0x00 for no string) 198 | * bmAttributes: 0xC0 for self powered 199 | * bMaxPower: 200 | */ 201 | 202 | #define USB_DESCR_BLOCK_CONFIGURATION(wTotalLength, bNumInterfaces, bConfigurationValue) \ 203 | 0x09, \ 204 | USB_DESC_TYPE_CONFIGURATION,\ 205 | LOBYTE(wTotalLength), \ 206 | HIBYTE(wTotalLength), \ 207 | bNumInterfaces, \ 208 | bConfigurationValue, \ 209 | USB_IDX_CONFIG_STR, \ 210 | 0xC0, \ 211 | USB_MAX_POWER 212 | 213 | 214 | /* 215 | * Descriptor block for describing interface associations (IAD) 216 | * bLength: Interface association descriptor size 217 | * bDescriptorType: IAD 218 | * bFirstInterface: First interface in the group 219 | * bInterfaceCount: Number of interfaces in the group 220 | * bFunctionClass: 221 | * bFunctionSubClass: 222 | * bFunctionProtocol: 223 | * iFunction: (0x00 for no string) 224 | */ 225 | #define USB_DESC_BLOCK_INTERFACE_ASSOCIATION(bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol) \ 226 | 0x08, \ 227 | USB_DESC_TYPE_INTERFACE_ASSOCIATION,\ 228 | bFirstInterface, \ 229 | bInterfaceCount, \ 230 | bFunctionClass, \ 231 | bFunctionSubClass, \ 232 | bFunctionProtocol, \ 233 | 0x00 234 | 235 | 236 | /* 237 | * PUBLIC TYPES 238 | */ 239 | 240 | typedef struct usb_setup_req 241 | { 242 | uint8_t bmRequest; 243 | uint8_t bRequest; 244 | uint16_t wValue; 245 | uint16_t wIndex; 246 | uint16_t wLength; 247 | } USB_SetupRequest_t; 248 | 249 | 250 | #endif // USB_DEFS_H 251 | -------------------------------------------------------------------------------- /tests/test_src/usb/cdc/USB_CDC.c: -------------------------------------------------------------------------------- 1 | 2 | #include "USB_CDC.h" 3 | 4 | #ifdef USB_CLASS_CDC 5 | #include "../USB_EP.h" 6 | #include "../USB_CTL.h" 7 | #include "Core.h" 8 | #include 9 | 10 | /* 11 | * PRIVATE DEFINITIONS 12 | */ 13 | 14 | #ifdef USB_CDC_BFR_SIZE 15 | #define CDC_BFR_SIZE USB_CDC_BFR_SIZE 16 | #else 17 | #define CDC_BFR_SIZE 512 18 | #endif 19 | 20 | #define CDC_BFR_WRAP(v) ((v) & (CDC_BFR_SIZE - 1)) 21 | 22 | #if (CDC_BFR_WRAP(CDC_BFR_SIZE) != 0) 23 | #error "USB_CDC_BFR_SIZE must be a power of two" 24 | #endif 25 | 26 | 27 | #define CDC_IN_EP 0x81 28 | #define CDC_OUT_EP 0x01 29 | #define CDC_CMD_EP 0x82 30 | 31 | #define CDC_BINTERVAL 0x10 32 | #define CDC_PACKET_SIZE USB_PACKET_SIZE 33 | #define CDC_CMD_PACKET_SIZE 8 34 | 35 | #define CDC_SEND_ENCAPSULATED_COMMAND 0x00U 36 | #define CDC_GET_ENCAPSULATED_RESPONSE 0x01U 37 | #define CDC_SET_COMM_FEATURE 0x02U 38 | #define CDC_GET_COMM_FEATURE 0x03U 39 | #define CDC_CLEAR_COMM_FEATURE 0x04U 40 | #define CDC_SET_LINE_CODING 0x20U 41 | #define CDC_GET_LINE_CODING 0x21U 42 | #define CDC_SET_CONTROL_LINE_STATE 0x22U 43 | #define CDC_SEND_BREAK 0x23U 44 | 45 | 46 | /* 47 | * PRIVATE TYPES 48 | */ 49 | 50 | typedef struct 51 | { 52 | uint8_t buffer[CDC_BFR_SIZE]; 53 | uint32_t head; 54 | uint32_t tail; 55 | } CDCBuffer_t; 56 | 57 | 58 | typedef struct 59 | { 60 | __IO bool txBusy; 61 | struct { 62 | uint8_t opcode; 63 | uint8_t size; 64 | // Not sure why this needs to be aligned? 65 | uint32_t data[CDC_CMD_PACKET_SIZE/4]; 66 | }cmd; 67 | uint8_t lineCoding[7]; 68 | } CDC_t; 69 | 70 | /* 71 | * PRIVATE PROTOTYPES 72 | */ 73 | 74 | static void USB_CDC_Control(uint8_t cmd, uint8_t* data, uint16_t length); 75 | static void USB_CDC_Receive(uint32_t count); 76 | static void USB_CDC_TransmitDone(uint32_t count); 77 | 78 | /* 79 | * PRIVATE VARIABLES 80 | */ 81 | 82 | 83 | __ALIGNED(4) const uint8_t cUSB_CDC_ConfigDescriptor[USB_CDC_CONFIG_DESC_SIZE] = 84 | { 85 | USB_DESCR_BLOCK_CONFIGURATION( 86 | USB_CDC_CONFIG_DESC_SIZE, 87 | 0x02, // two interfaces available 88 | 0x01 89 | ), 90 | USB_DESCR_BLOCK_INTERFACE( 91 | 0x00, 92 | 0x01, // 1 endpoint used 93 | 0x02, // Communication Interface Class 94 | 0x02, // Abstract Control Model 95 | 0x01 // Common AT commands 96 | ), 97 | 98 | // Header Functional Descriptor 99 | 0x05, // bLength: Endpoint Descriptor size 100 | 0x24, // bDescriptorType: CS_INTERFACE 101 | 0x00, // bDescriptorSubtype: Header Func Desc 102 | 0x10, // bcdCDC: spec release number 103 | 0x01, 104 | 105 | // Call Management Functional Descriptor 106 | 0x05, // bFunctionLength 107 | 0x24, // bDescriptorType: CS_INTERFACE 108 | 0x01, // bDescriptorSubtype: Call Management Func Desc 109 | 0x00, // bmCapabilities: D0+D1 110 | 0x01, // bDataInterface: 1 111 | 112 | // ACM Functional Descriptor 113 | 0x04, // bFunctionLength 114 | 0x24, // bDescriptorType: CS_INTERFACE 115 | 0x02, // bDescriptorSubtype: Abstract Control Management desc 116 | 0x02, // bmCapabilities 117 | 118 | // Union Functional Descriptor 119 | 0x05, // bFunctionLength 120 | 0x24, // bDescriptorType: CS_INTERFACE 121 | 0x06, // bDescriptorSubtype: Union func desc 122 | 0x00, // bMasterInterface: Communication class interface 123 | 0x01, // bSlaveInterface0: Data Class Interface 124 | 125 | // Endpoint 2 Descriptor 126 | USB_DESCR_BLOCK_ENDPOINT(CDC_CMD_EP, 0x03, CDC_CMD_PACKET_SIZE, CDC_BINTERVAL), 127 | 128 | USB_DESCR_BLOCK_INTERFACE( 129 | 0x01, 130 | 0x02, // 2 endpoints used 131 | 0x0A, // Communication Device Class 132 | 0x00, // Abstract Control Model 133 | 0x00 // Common AT commands 134 | ), 135 | USB_DESCR_BLOCK_ENDPOINT(CDC_OUT_EP, 0x02, CDC_PACKET_SIZE, 0x00), // Bulk endpoint 136 | USB_DESCR_BLOCK_ENDPOINT(CDC_IN_EP, 0x02, CDC_PACKET_SIZE, 0x00), // Bulk endpoint 137 | }; 138 | 139 | static uint8_t gRxBuffer[CDC_PACKET_SIZE]; 140 | static CDCBuffer_t gRx; 141 | 142 | static CDC_t gCDC; 143 | 144 | /* 145 | * PUBLIC FUNCTIONS 146 | */ 147 | 148 | void USB_CDC_Init(uint8_t config) 149 | { 150 | gRx.head = gRx.tail = 0; 151 | gCDC.txBusy = false; 152 | 153 | // Data endpoints 154 | USB_EP_Open(CDC_IN_EP, USB_EP_TYPE_BULK, CDC_PACKET_SIZE, USB_CDC_TransmitDone); 155 | USB_EP_Open(CDC_OUT_EP, USB_EP_TYPE_BULK, CDC_PACKET_SIZE, USB_CDC_Receive); 156 | USB_EP_Open(CDC_CMD_EP, USB_EP_TYPE_BULK, CDC_CMD_PACKET_SIZE, USB_CDC_Receive); 157 | 158 | USB_EP_Read(CDC_OUT_EP, gRxBuffer, CDC_PACKET_SIZE); 159 | 160 | // 115200bps, 1stop, no parity, 8bit 161 | uint8_t lineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 }; 162 | memcpy(gCDC.lineCoding, lineCoding, sizeof(gCDC.lineCoding)); 163 | } 164 | 165 | void USB_CDC_Deinit(void) 166 | { 167 | USB_EP_Close(CDC_IN_EP); 168 | USB_EP_Close(CDC_OUT_EP); 169 | USB_EP_Close(CDC_CMD_EP); 170 | gRx.head = gRx.tail = 0; 171 | } 172 | 173 | void USB_CDC_Write(const uint8_t * data, uint32_t count) 174 | { 175 | // This will block if the transmitter is not free, or multiple packets are sent out. 176 | uint32_t tide = CORE_GetTick(); 177 | while (count) 178 | { 179 | if (gCDC.txBusy) 180 | { 181 | // Wait for transmit to be free. Abort if it does not come free. 182 | if (CORE_GetTick() - tide > 10) 183 | { 184 | break; 185 | } 186 | CORE_Idle(); 187 | } 188 | else 189 | { 190 | // Transmit a packet 191 | // We send packets of length 63. This gets around an issue where windows can drop full sized serial packets. 192 | uint32_t packet_size = count > (CDC_PACKET_SIZE - 1) ? (CDC_PACKET_SIZE - 1) : count; 193 | gCDC.txBusy = true; 194 | USB_EP_Write(CDC_IN_EP, data, packet_size); 195 | count -= packet_size; 196 | data += packet_size; 197 | } 198 | } 199 | } 200 | 201 | uint32_t USB_CDC_ReadReady(void) 202 | { 203 | // Assume these reads are atomic 204 | uint32_t count = CDC_BFR_WRAP(gRx.head - gRx.tail); 205 | return count; 206 | } 207 | 208 | uint32_t USB_CDC_Read(uint8_t * data, uint32_t count) 209 | { 210 | uint32_t ready = USB_CDC_ReadReady(); 211 | 212 | if (count > ready) 213 | { 214 | count = ready; 215 | } 216 | if (count > 0) 217 | { 218 | uint32_t tail = gRx.tail; 219 | uint32_t newtail = CDC_BFR_WRAP( tail + count ); 220 | if (newtail > tail) 221 | { 222 | // We can read continuously from the buffer 223 | memcpy(data, gRx.buffer + tail, count); 224 | } 225 | else 226 | { 227 | // We read to end of buffer, then read from the start 228 | uint32_t chunk = CDC_BFR_SIZE - tail; 229 | memcpy(data, gRx.buffer + tail, chunk); 230 | memcpy(data + chunk, gRx.buffer, count - chunk); 231 | } 232 | gRx.tail = newtail; 233 | } 234 | return count; 235 | } 236 | 237 | void USB_CDC_CtlRxReady(void) 238 | { 239 | if (gCDC.cmd.opcode != 0xFF) 240 | { 241 | USB_CDC_Control(gCDC.cmd.opcode, (uint8_t *)gCDC.cmd.data, gCDC.cmd.size); 242 | gCDC.cmd.opcode = 0xFF; 243 | } 244 | } 245 | 246 | void USB_CDC_Setup(USB_SetupRequest_t * req) 247 | { 248 | if (req->wLength) 249 | { 250 | if (req->bmRequest & 0x80U) 251 | { 252 | USB_CDC_Control(req->bRequest, (uint8_t *)gCDC.cmd.data, req->wLength); 253 | USB_CTL_Send((uint8_t *)gCDC.cmd.data, req->wLength); 254 | } 255 | else 256 | { 257 | gCDC.cmd.opcode = req->bRequest; 258 | gCDC.cmd.size = req->wLength; 259 | USB_CTL_Receive((uint8_t *)gCDC.cmd.data, req->wLength); 260 | } 261 | } 262 | else 263 | { 264 | USB_CDC_Control(req->bRequest, (uint8_t *)req, 0U); 265 | } 266 | } 267 | 268 | /* 269 | * PRIVATE FUNCTIONS 270 | */ 271 | 272 | static void USB_CDC_Control(uint8_t cmd, uint8_t* data, uint16_t length) 273 | { 274 | switch(cmd) 275 | { 276 | case CDC_SET_LINE_CODING: 277 | memcpy(gCDC.lineCoding, data, sizeof(gCDC.lineCoding)); 278 | break; 279 | case CDC_GET_LINE_CODING: 280 | memcpy(data, gCDC.lineCoding, sizeof(gCDC.lineCoding)); 281 | break; 282 | case CDC_SEND_ENCAPSULATED_COMMAND: 283 | case CDC_GET_ENCAPSULATED_RESPONSE: 284 | case CDC_SET_COMM_FEATURE: 285 | case CDC_GET_COMM_FEATURE: 286 | case CDC_CLEAR_COMM_FEATURE: 287 | case CDC_SET_CONTROL_LINE_STATE: 288 | case CDC_SEND_BREAK: 289 | default: 290 | break; 291 | } 292 | } 293 | 294 | static void USB_CDC_Receive(uint32_t count) 295 | { 296 | // Minus 1 because head == tail represents the empty condition. 297 | uint32_t space = CDC_BFR_WRAP(gRx.tail - gRx.head - 1); 298 | 299 | if (count > space) 300 | { 301 | // Discard any data that we cannot insert into the buffer. 302 | count = space; 303 | } 304 | if (count > 0) 305 | { 306 | uint32_t head = gRx.head; 307 | uint32_t newhead = CDC_BFR_WRAP( head + count ); 308 | if (newhead > head) 309 | { 310 | // We can write continuously into the buffer 311 | memcpy(gRx.buffer + head, gRxBuffer, count); 312 | } 313 | else 314 | { 315 | // We write to end of buffer, then write from the start 316 | uint32_t chunk = CDC_BFR_SIZE - head; 317 | memcpy(gRx.buffer + head, gRxBuffer, chunk); 318 | memcpy(gRx.buffer, gRxBuffer + chunk, count - chunk); 319 | } 320 | gRx.head = newhead; 321 | } 322 | 323 | USB_EP_Read(CDC_OUT_EP, gRxBuffer, CDC_PACKET_SIZE); 324 | } 325 | 326 | static void USB_CDC_TransmitDone(uint32_t count) 327 | { 328 | if (count > 0 && (count % CDC_PACKET_SIZE) == 0) 329 | { 330 | // Write a ZLP to complete the tx. 331 | USB_EP_WriteZLP(CDC_IN_EP); 332 | } 333 | else 334 | { 335 | gCDC.txBusy = false; 336 | } 337 | } 338 | 339 | #endif //USB_CLASS_CDC 340 | 341 | -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import sys 3 | 4 | # Hack to include module in base directory 5 | sys.path.insert(0, os.path.abspath('./')) 6 | from preprocessor import Preprocessor 7 | 8 | SRC_PATH = "tests/test_src" 9 | 10 | def test_assert(expr, expected): 11 | if expr != expected: 12 | raise AssertionError("Expected {}, got {}".format(expected, expr)) 13 | 14 | 15 | 16 | # Tests that a macro can be evaluated 17 | def test_macro_evaluation(): 18 | p = Preprocessor() 19 | 20 | p.define("MACRO_CONST", "0x1") 21 | p.define("MACRO_A", "(a + b)", ["a","b"]) 22 | p.define("MACRO_B", "(a + MACRO_CONST)", ["a"]) 23 | p.define("MACRO_C", "(MACRO_A(a, 1) + MACRO_B(b))", ["a", "b"]) 24 | p.define("MACRO_D", "(v & (512 - 1))", "v") 25 | p.define("MACRO_E", "23", []) 26 | 27 | # test basic macro evaluation works 28 | test_assert(p.evaluate("(3 + 4) / 2"), 3) 29 | test_assert(p.evaluate("MACRO_CONST + 1"), 2) 30 | test_assert(p.evaluate("MACRO_A(1, 2)"), 3) 31 | test_assert(p.evaluate("MACRO_B(10)"), 11) 32 | test_assert(p.evaluate("MACRO_C(1, 2)"), 5) 33 | test_assert(p.evaluate("MACRO_D(512 + MACRO_CONST)"), 1) 34 | test_assert(p.evaluate("MACRO_E()"), 23) 35 | 36 | # Function-like macros should not be expanded if no arguments are provided. 37 | test_assert(p.expand("MACRO_E"), "MACRO_E") 38 | 39 | # a few more tests to check evaulation 40 | test_assert(p.evaluate("3 - 4"), -1) 41 | test_assert(p.evaluate("3 == 5"), False) 42 | test_assert(p.evaluate("3 != 5"), True) 43 | test_assert(p.evaluate("!(1)"), False) 44 | 45 | test_assert(p.evaluate("defined(MACRO_Z)"), False) 46 | test_assert(p.evaluate("defined(MACRO_A)"), True) 47 | 48 | # Test empty macros 49 | def test_empty_macros(): 50 | p = Preprocessor() 51 | 52 | p.define("MACRO_A") 53 | p.define("MACRO_B", args=["a", "b"]) 54 | 55 | # Check that the macro expands to an empty string 56 | test_assert(p.expand("MACRO_A"), "") 57 | test_assert(p.expand("MACRO_B(1,2)"), "") 58 | 59 | # Tests that a recursive macro does not block execution 60 | def test_recursive_macro(): 61 | p = Preprocessor() 62 | 63 | p.define("MACRO_A", "MACRO_B") 64 | p.define("MACRO_B", "MACRO_A") 65 | 66 | try: 67 | p.evaluate("MACRO_A") 68 | test_assert("The expression above should fail.", None) 69 | except: 70 | pass 71 | 72 | 73 | # Tests for conditional directives 74 | def test_conditional_directives(): 75 | src = """ 76 | #if defined(CASE_A) 77 | #define MACRO_A 1 78 | #elif (CASE_B == 1) 79 | #define MACRO_A 2 80 | #else 81 | #define MACRO_A 3 82 | #endif 83 | """ 84 | 85 | p = Preprocessor() 86 | p.define("CASE_A") 87 | p.include("source.c",src) 88 | test_assert(p.evaluate("MACRO_A"), 1) 89 | 90 | p = Preprocessor() 91 | p.define("CASE_B", "1") 92 | p.include("source.c",src) 93 | test_assert(p.evaluate("MACRO_A"), 2) 94 | 95 | p = Preprocessor() 96 | p.undefine("CASE_B") 97 | p.include("source.c",src) 98 | test_assert(p.evaluate("MACRO_A"), 3) 99 | 100 | # Tests for checking that #directives with spaces still work 101 | def test_spaced_directives(): 102 | p = Preprocessor() 103 | src = """ 104 | #define SYMBOL_A 1 105 | # define SYMBOL_B 2 106 | # define SYMBOL_C 3 107 | #define SYMBOL_D 4 108 | #define SYMBOL_E 5 109 | """ 110 | p.include("source.c", src) 111 | # Just check that all symbols got defined, and can be resovled. 112 | test_assert(p.expand("SYMBOL_A,SYMBOL_B,SYMBOL_C,SYMBOL_D,SYMBOL_E"), "1,2,3,4,5") 113 | 114 | # Tests for including a file 115 | def test_include(): 116 | p = Preprocessor() 117 | p.add_include_path(SRC_PATH) 118 | p.include("test.h") 119 | 120 | test_assert(p.evaluate("MACRO_A(1, 2)"), 3) 121 | test_assert(p.evaluate("MACRO_B(1)"), 2) 122 | test_assert(p.evaluate("MACRO_C(1, 2)"), 5) 123 | test_assert(p.evaluate("MACRO_D(513)"), 1) 124 | 125 | # Now check that #includes embedded within source are executed. 126 | p = Preprocessor() 127 | p.add_include_path(SRC_PATH) 128 | p.include("dummy.c", ''' #include ''') 129 | test_assert(p.evaluate("MACRO_D(513)"), 1) 130 | 131 | # Now check that macro expansion works within these #includes. 132 | p = Preprocessor() 133 | p.add_include_path(SRC_PATH) 134 | p.define("FILENAME", '"test.h"') 135 | p.include("dummy.c", ''' #include FILENAME ''') 136 | test_assert(p.evaluate("MACRO_D(513)"), 1) 137 | 138 | def test_whitespace_strip(): 139 | p = Preprocessor() 140 | src = """ 141 | #define MACRO_SPACED_PARAMS(a, b, c,d) a b c d 142 | #define MACRO_SPACED_ARGS(a, b, c, d) a b c d 143 | """ 144 | p.include("source.c", src) 145 | 146 | test_assert(p.expand("MACRO_SPACED_PARAMS(1, 2, 3, 4)"), "1 2 3 4") 147 | test_assert(p.expand("MACRO_SPACED_ARGS(1, 2,3, 4)"), "1 2 3 4") 148 | 149 | # Tests for variadic parameters in macros 150 | def test_va_args(): 151 | p = Preprocessor() 152 | p.define("MACRO_VA_ARG_IDENTITY", "__VA_ARGS__", ["..."]) 153 | p.define("MACRO_NAMED_VA_ARG_IDENTITY", "x", ["x..."]) 154 | p.define("MACRO_VA_ARG_COHERENCE", "a@x", ["a", "x..."]) 155 | p.define("MACRO_VA_ARG_INVALID", "a@x", ["a...", "x"]) 156 | p.define("MACRO_VA_ARG_INVALID2", "a@x", ["a...", "x..."]) 157 | p.define("MACRO_INVALID", "a@x", ["a", "x...."]) 158 | 159 | test_assert(p.expand('MACRO_VA_ARG_IDENTITY(1, 2 3, "abc")'), '1, 2 3, "abc"') 160 | test_assert(p.expand('MACRO_NAMED_VA_ARG_IDENTITY(1, 2 3, "abc")'), '1, 2 3, "abc"') 161 | # Note that spaces are not .strip()-ped in variadic macros 162 | test_assert(p.expand("MACRO_VA_ARG_COHERENCE(contact test,domain.tld, or call +0123456789 for further assistance)"), 163 | "contact test@domain.tld, or call +0123456789 for further assistance") 164 | 165 | try: 166 | p.evaluate("MACRO_VA_ARG_INVALID(a b c, d, e)") 167 | test_assert("The expression above should fail.", None) 168 | except: 169 | pass 170 | 171 | try: 172 | p.evaluate("MACRO_VA_ARG_INVALID2(a b c, d, e)") 173 | test_assert("The expression above should fail.", None) 174 | except: 175 | pass 176 | 177 | try: 178 | p.evaluate("MACRO_INVALID(a b c, d, e)") 179 | test_assert("The expression above should fail.", None) 180 | except: 181 | pass 182 | 183 | # tests that macros with embedded in strings are correctly handled 184 | def test_string_embedded_macros(): 185 | p = Preprocessor() 186 | p.define("MACRO_CONST", "0x1") 187 | p.define("MACRO_A", "(a + b)", ["a","b"]) 188 | p.define("MACRO_B", "(a + 1)", ["a"]) 189 | 190 | # check for macro expansion in strings 191 | # Note, this is incorrect logic for C string gluing, but it is a good test 192 | test_assert(p.evaluate('MACRO_A("TEXT ","MACRO_CONST")'), "TEXT MACRO_CONST") 193 | 194 | # check for macro expansion in strings 195 | test_assert(p.evaluate('"MACRO_A(1,MACRO_B(2))"'), "MACRO_A(1,MACRO_B(2))") 196 | 197 | # check for parenthesis and commas in strings 198 | test_assert(p.evaluate('MACRO_A("TEXT, ", ")")'), "TEXT, )") 199 | 200 | # check for escaped symbols in strings 201 | test_assert(p.evaluate('MACRO_A("\'\\\\ \\" ","TEXT")'), "'\\ \" TEXT") 202 | 203 | 204 | # tests that macros with with nested arguments are correctly handled 205 | def test_nested_macros(): 206 | p = Preprocessor() 207 | p.define("MACRO_CONST", "0x1") 208 | p.define("MACRO_A", "(a + b)", ["a","b"]) 209 | p.define("MACRO_B", "(a + 1)", ["a"]) 210 | p.define("MACRO_C", "MACRO_B") 211 | 212 | # check for nested macros 213 | test_assert(p.evaluate("MACRO_A(1,MACRO_B(2))"), 4) 214 | 215 | # check alternate spacing 216 | test_assert(p.evaluate("MACRO_A ( 1, MACRO_CONST )"), 2) 217 | 218 | # try other orientation 219 | test_assert(p.evaluate("MACRO_A(MACRO_B( 2 ), 1)"), 4) 220 | 221 | # check that nested macros with commas work 222 | test_assert(p.evaluate("MACRO_A(1, MACRO_A(3,4))"), 8) 223 | 224 | # check a heavily nested macro 225 | test_assert(p.evaluate("MACRO_A(1, MACRO_B(MACRO_A(3,MACRO_B(1))))"), 7) 226 | 227 | # A non arg macro that expands into an argument macro 228 | test_assert(p.evaluate("MACRO_C(1)"), 2) 229 | 230 | 231 | # Test that source is correctly expanded 232 | def test_source_expansion(): 233 | p = Preprocessor() 234 | 235 | # Include a piece of source with some macros to be expanded. 236 | # Note the multiline macro expansion. 237 | 238 | p.define("MACRO_CONST", "3") 239 | p.include("main.c", """ 240 | 241 | #define MACRO_A(a,b) (a + b) 242 | #define MACRO_B(a,b) MACRO_A(a, MACRO_A(1, b)) 243 | 244 | int void main(void) 245 | { 246 | int a = MACRO_A(1,2); 247 | return MACRO_B( 248 | a, 249 | MACRO_CONST 250 | ); 251 | } 252 | 253 | """) 254 | 255 | expected = """ 256 | int void main(void) 257 | { 258 | int a = (1 + 2); 259 | return (a + (1 + 3)); 260 | } 261 | """ 262 | 263 | # Remove whitespace - too much of a pain to test. 264 | def trim_whitespace(s): 265 | return " ".join(s.split()) 266 | 267 | # Check that the source is expanded correctly 268 | source = p.source() 269 | test_assert(trim_whitespace(source), trim_whitespace(expected)) 270 | 271 | 272 | # Real world test cases using the USB MSC example 273 | def test_usb_class_msc(): 274 | p = Preprocessor() 275 | p.ignore_missing_includes = True 276 | p.add_include_path(SRC_PATH) 277 | 278 | p.define("USB_CLASS_MSC") 279 | p.include("usb/USB_Class.h") 280 | 281 | test_assert(p.expand("USB_INTERFACES"), "1") 282 | test_assert(p.expand("USB_ENDPOINTS"), "2") 283 | test_assert(p.expand("USB_CLASS_DEVICE_DESCRIPTOR"), "cUSB_MSC_ConfigDescriptor") 284 | test_assert(p.expand("USB_CLASS_INIT(0)"), "USB_MSC_Init(0)") 285 | 286 | # Real world test cases using the USB CDC example 287 | def test_usb_class_cdc(): 288 | p = Preprocessor() 289 | p.ignore_missing_includes = True 290 | p.add_include_path(SRC_PATH) 291 | 292 | p.define("USB_CLASS_CDC") 293 | p.include("usb/USB_Class.h") 294 | 295 | test_assert(p.expand("USB_INTERFACES"), "2") 296 | test_assert(p.expand("USB_ENDPOINTS"), "3") 297 | test_assert(p.expand("USB_CLASS_DEVICE_DESCRIPTOR"), "cUSB_CDC_ConfigDescriptor") 298 | test_assert(p.expand("USB_CLASS_INIT(0)"), "USB_CDC_Init(0)") 299 | 300 | # Include a source file with a lot of source 301 | def test_include_source(): 302 | p = Preprocessor() 303 | p.ignore_missing_includes = True 304 | p.add_include_path(SRC_PATH) 305 | 306 | p.include("usb/cdc/USB_CDC.c") 307 | p.source() 308 | 309 | # Run all the tests 310 | def run_tests(): 311 | test_macro_evaluation() 312 | test_empty_macros() 313 | test_recursive_macro() 314 | test_conditional_directives() 315 | test_spaced_directives() 316 | test_include() 317 | test_whitespace_strip() 318 | test_va_args() 319 | test_string_embedded_macros() 320 | test_nested_macros() 321 | test_source_expansion() 322 | test_usb_class_msc() 323 | test_usb_class_cdc() 324 | test_include_source() 325 | 326 | if __name__ == "__main__": 327 | run_tests() 328 | -------------------------------------------------------------------------------- /tests/test_src/usb/msc/SCSI.c: -------------------------------------------------------------------------------- 1 | #include "SCSI.h" 2 | #include "USB_MSC.h" 3 | #include 4 | 5 | /* 6 | * PRIVATE DEFINITIONS 7 | */ 8 | 9 | // Response sizes 10 | #define INQUIRY_PAGE00_LEN 0x07 11 | #define MODE_SENSE10_LEN 0x08 12 | #define MODE_SENSE6_LEN 0x08 13 | #define REQUEST_SENSE_LEN 0x12 14 | #define READ_FORMAT_CAPACITY_LEN 0x0C 15 | #define READ_CAPACITY10_LEN 0x08 16 | 17 | 18 | // SCSI Commands 19 | #define SCSI_FORMAT_UNIT 0x04 20 | #define SCSI_INQUIRY 0x12 21 | #define SCSI_MODE_SELECT6 0x15 22 | #define SCSI_MODE_SELECT10 0x55 23 | #define SCSI_MODE_SENSE6 0x1A 24 | #define SCSI_MODE_SENSE10 0x5A 25 | #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E 26 | #define SCSI_READ6 0x08 27 | #define SCSI_READ10 0x28 28 | #define SCSI_READ12 0xA8 29 | #define SCSI_READ16 0x88 30 | 31 | #define SCSI_READ_CAPACITY10 0x25 32 | #define SCSI_READ_CAPACITY16 0x9E 33 | 34 | #define SCSI_REQUEST_SENSE 0x03 35 | #define SCSI_START_STOP_UNIT 0x1B 36 | #define SCSI_TEST_UNIT_READY 0x00 37 | #define SCSI_WRITE6 0x0A 38 | #define SCSI_WRITE10 0x2A 39 | #define SCSI_WRITE12 0xAA 40 | #define SCSI_WRITE16 0x8A 41 | 42 | #define SCSI_VERIFY10 0x2F 43 | #define SCSI_VERIFY12 0xAF 44 | #define SCSI_VERIFY16 0x8F 45 | 46 | #define SCSI_SEND_DIAGNOSTIC 0x1D 47 | #define SCSI_READ_FORMAT_CAPACITIES 0x23 48 | 49 | // SCSI errors 50 | #define SCSI_SKEY_NO_SENSE 0 51 | #define SCSI_SKEY_RECOVERED_ERROR 1 52 | #define SCSI_SKEY_NOT_READY 2 53 | #define SCSI_SKEY_MEDIUM_ERROR 3 54 | #define SCSI_SKEY_HARDWARE_ERROR 4 55 | #define SCSI_SKEY_ILLEGAL_REQUEST 5 56 | #define SCSI_SKEY_UNIT_ATTENTION 6 57 | #define SCSI_SKEY_DATA_PROTECT 7 58 | #define SCSI_SKEY_BLANK_CHECK 8 59 | #define SCSI_SKEY_VENDOR_SPECIFIC 9 60 | #define SCSI_SKEY_COPY_ABORTED 10 61 | #define SCSI_SKEY_ABORTED_COMMAND 11 62 | #define SCSI_SKEY_VOLUME_OVERFLOW 13 63 | #define SCSI_SKEY_MISCOMPARE 14 64 | 65 | #define SCSI_ASQ_INVALID_CDB 0x20 66 | #define SCSI_ASQ_INVALID_FIELD_IN_COMMAND 0x24 67 | #define SCSI_ASQ_PARAMETER_LIST_LENGTH_ERROR 0x1A 68 | #define SCSI_ASQ_INVALID_FIELD_IN_PARAMETER_LIST 0x26 69 | #define SCSI_ASQ_ADDRESS_OUT_OF_RANGE 0x21 70 | #define SCSI_ASQ_MEDIUM_NOT_PRESENT 0x3A 71 | #define SCSI_ASQ_MEDIUM_HAVE_CHANGED 0x28 72 | #define SCSI_ASQ_WRITE_PROTECTED 0x27 73 | #define SCSI_ASQ_UNRECOVERED_READ_ERROR 0x11 74 | #define SCSI_ASQ_WRITE_FAULT 0x03 75 | 76 | /* 77 | * PRIVATE TYPES 78 | */ 79 | 80 | /* 81 | * PRIVATE PROTOTYPES 82 | */ 83 | 84 | static SCSI_State_t SCSI_SenseCode(SCSI_t * scsi, uint8_t sKey, uint8_t ASC); 85 | 86 | static SCSI_State_t SCSI_TestUnitReady(SCSI_t * scsi, SCSI_CBW_t * cbw); 87 | static SCSI_State_t SCSI_Inquiry(SCSI_t * scsi, SCSI_CBW_t * cbw); 88 | static SCSI_State_t SCSI_ReadFormatCapacity(SCSI_t * scsi, SCSI_CBW_t * cbw); 89 | static SCSI_State_t SCSI_ReadCapacity10(SCSI_t * scsi, SCSI_CBW_t * cbw); 90 | static SCSI_State_t SCSI_RequestSense(SCSI_t * scsi, SCSI_CBW_t * cbw); 91 | static SCSI_State_t SCSI_StartStopUnit(SCSI_t * scsi, SCSI_CBW_t * cbw); 92 | static SCSI_State_t SCSI_ModeSense6(SCSI_t * scsi, SCSI_CBW_t * cbw); 93 | static SCSI_State_t SCSI_ModeSense10(SCSI_t * scsi, SCSI_CBW_t * cbw); 94 | static SCSI_State_t SCSI_Write10(SCSI_t * scsi, SCSI_CBW_t * cbw); 95 | static SCSI_State_t SCSI_Read10(SCSI_t * scsi, SCSI_CBW_t * cbw); 96 | static SCSI_State_t SCSI_Verify10(SCSI_t * scsi, SCSI_CBW_t * cbw); 97 | static SCSI_State_t SCSI_CheckAddressRange(SCSI_t * scsi, uint32_t blk_offset, uint32_t blk_nbr); 98 | 99 | static SCSI_State_t SCSI_ProcessRead(SCSI_t * scsi); 100 | static SCSI_State_t SCSI_ProcessWrite(SCSI_t * scsi); 101 | 102 | /* 103 | * PRIVATE VARIABLES 104 | */ 105 | 106 | const uint8_t cSCSI_InquiryPage00[] = 107 | { 108 | 0x00, 109 | 0x00, 110 | 0x00, 111 | (INQUIRY_PAGE00_LEN - 4), 112 | 0x00, 113 | 0x80, 114 | 0x83 115 | }; 116 | 117 | const uint8_t cSCSI_InquiryPage[] = {/* 36 */ 118 | 0x00, 119 | 0x80, 120 | 0x02, 121 | 0x02, 122 | (0x24 - 5), 123 | 0x00, 124 | 0x00, 125 | 0x00, 126 | 'L', 'a', 'm', 'b', 'o', ' ', ' ', ' ', /* Manufacturer : 8 bytes */ 127 | 'S', 'T', 'M', '3', '2', 'X', ' ', 'M', /* Product : 16 Bytes */ 128 | 'S', 'C', ' ', ' ', ' ', ' ', ' ', ' ', 129 | '1', '.', '0' ,'0' /* Version : 4 Bytes */ 130 | }; 131 | 132 | /* 133 | * PUBLIC FUNCTIONS 134 | */ 135 | 136 | SCSI_State_t SCSI_Init(SCSI_t * scsi, const USB_Storage_t * storage) 137 | { 138 | scsi->sense.head = 0; 139 | scsi->sense.tail = 0; 140 | scsi->storage = NULL; // NULL storage indicates no disk. 141 | if (storage != NULL && storage->open(&scsi->block_count)) 142 | { 143 | scsi->storage = storage; 144 | } 145 | return SCSI_State_Ok; 146 | } 147 | 148 | SCSI_State_t SCSI_ProcessCmd(SCSI_t * scsi, SCSI_CBW_t * cbw) 149 | { 150 | switch (cbw->CB[0]) 151 | { 152 | case SCSI_TEST_UNIT_READY: 153 | return SCSI_TestUnitReady(scsi, cbw); 154 | case SCSI_REQUEST_SENSE: 155 | return SCSI_RequestSense(scsi, cbw); 156 | case SCSI_INQUIRY: 157 | return SCSI_Inquiry(scsi, cbw); 158 | case SCSI_START_STOP_UNIT: 159 | return SCSI_StartStopUnit(scsi, cbw); 160 | case SCSI_ALLOW_MEDIUM_REMOVAL: 161 | return SCSI_StartStopUnit(scsi, cbw); 162 | case SCSI_MODE_SENSE6: 163 | return SCSI_ModeSense6(scsi, cbw); 164 | case SCSI_MODE_SENSE10: 165 | return SCSI_ModeSense10(scsi, cbw); 166 | case SCSI_READ_FORMAT_CAPACITIES: 167 | return SCSI_ReadFormatCapacity(scsi, cbw); 168 | case SCSI_READ_CAPACITY10: 169 | return SCSI_ReadCapacity10(scsi, cbw); 170 | case SCSI_READ10: 171 | return SCSI_Read10(scsi, cbw); 172 | case SCSI_WRITE10: 173 | return SCSI_Write10(scsi, cbw); 174 | case SCSI_VERIFY10: 175 | return SCSI_Verify10(scsi, cbw); 176 | default: 177 | return SCSI_SenseCode(scsi, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASQ_INVALID_CDB); 178 | } 179 | } 180 | 181 | SCSI_State_t SCSI_ResumeCmd(SCSI_t * scsi, SCSI_State_t state) 182 | { 183 | switch (state) 184 | { 185 | case SCSI_State_DataOut: 186 | return SCSI_ProcessWrite(scsi); 187 | 188 | case SCSI_State_DataIn: 189 | return SCSI_ProcessRead(scsi); 190 | 191 | case SCSI_State_SendData: 192 | case SCSI_State_LastDataIn: 193 | return SCSI_State_Ok; 194 | 195 | default: 196 | return SCSI_State_Error; 197 | } 198 | } 199 | 200 | /* 201 | * PRIVATE FUNCTIONS 202 | */ 203 | 204 | static SCSI_State_t SCSI_TestUnitReady(SCSI_t * scsi, SCSI_CBW_t * cbw) 205 | { 206 | if (cbw->dDataLength != 0) 207 | { 208 | return SCSI_SenseCode(scsi, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASQ_INVALID_CDB); 209 | } 210 | if (scsi->storage == NULL) 211 | { 212 | return SCSI_SenseCode(scsi, SCSI_SKEY_NOT_READY, SCSI_ASQ_MEDIUM_NOT_PRESENT); 213 | } 214 | return SCSI_State_Ok; 215 | } 216 | 217 | static SCSI_State_t SCSI_Inquiry(SCSI_t * scsi, SCSI_CBW_t * cbw) 218 | { 219 | uint16_t len; 220 | const uint8_t * page; 221 | 222 | if (cbw->CB[1] & 0x01U) // Evpd is set 223 | { 224 | page = cSCSI_InquiryPage00; 225 | len = INQUIRY_PAGE00_LEN; 226 | } 227 | else 228 | { 229 | page = cSCSI_InquiryPage; 230 | len = (uint16_t)page[4] + 5U; 231 | 232 | if (cbw->CB[4] <= len) 233 | { 234 | len = cbw->CB[4]; 235 | } 236 | } 237 | 238 | memcpy(scsi->bfr, page, len); 239 | scsi->data_len = len; 240 | return SCSI_State_SendData; 241 | } 242 | 243 | static SCSI_State_t SCSI_ReadCapacity10(SCSI_t * scsi, SCSI_CBW_t * cbw) 244 | { 245 | if (scsi->storage == NULL) 246 | { 247 | return SCSI_SenseCode(scsi, SCSI_SKEY_NOT_READY, SCSI_ASQ_MEDIUM_NOT_PRESENT); 248 | } 249 | else 250 | { 251 | uint32_t blk_nbr = scsi->block_count - 1; 252 | 253 | scsi->bfr[0] = (uint8_t)(blk_nbr >> 24); 254 | scsi->bfr[1] = (uint8_t)(blk_nbr >> 16); 255 | scsi->bfr[2] = (uint8_t)(blk_nbr >> 8); 256 | scsi->bfr[3] = (uint8_t)(blk_nbr); 257 | 258 | scsi->bfr[4] = (uint8_t)(SCSI_BLOCK_SIZE >> 24); 259 | scsi->bfr[5] = (uint8_t)(SCSI_BLOCK_SIZE >> 16); 260 | scsi->bfr[6] = (uint8_t)(SCSI_BLOCK_SIZE >> 8); 261 | scsi->bfr[7] = (uint8_t)(SCSI_BLOCK_SIZE); 262 | 263 | scsi->data_len = READ_CAPACITY10_LEN; 264 | return SCSI_State_SendData; 265 | } 266 | } 267 | 268 | static SCSI_State_t SCSI_ReadFormatCapacity(SCSI_t * scsi, SCSI_CBW_t * cbw) 269 | { 270 | if (scsi->storage == NULL) 271 | { 272 | return SCSI_SenseCode(scsi, SCSI_SKEY_NOT_READY, SCSI_ASQ_MEDIUM_NOT_PRESENT); 273 | } 274 | else 275 | { 276 | uint32_t blk_nbr = scsi->block_count - 1; 277 | 278 | scsi->bfr[0] = 0x00; 279 | scsi->bfr[1] = 0x00; 280 | scsi->bfr[2] = 0x00; 281 | scsi->bfr[3] = 0x08U; 282 | scsi->bfr[4] = (uint8_t)(blk_nbr >> 24); 283 | scsi->bfr[5] = (uint8_t)(blk_nbr >> 16); 284 | scsi->bfr[6] = (uint8_t)(blk_nbr >> 8); 285 | scsi->bfr[7] = (uint8_t)blk_nbr; 286 | 287 | scsi->bfr[8] = 0x02U; 288 | scsi->bfr[9] = (uint8_t)(SCSI_BLOCK_SIZE >> 16); 289 | scsi->bfr[10] = (uint8_t)(SCSI_BLOCK_SIZE >> 8); 290 | scsi->bfr[11] = (uint8_t)(SCSI_BLOCK_SIZE); 291 | 292 | scsi->data_len = READ_FORMAT_CAPACITY_LEN; 293 | return SCSI_State_SendData; 294 | } 295 | } 296 | 297 | static SCSI_State_t SCSI_ModeSense6(SCSI_t * scsi, SCSI_CBW_t * cbw) 298 | { 299 | memset(scsi->bfr, 0, MODE_SENSE6_LEN); 300 | scsi->data_len = MODE_SENSE6_LEN; 301 | return SCSI_State_SendData; 302 | } 303 | 304 | static SCSI_State_t SCSI_ModeSense10(SCSI_t * scsi, SCSI_CBW_t * cbw) 305 | { 306 | memset(scsi->bfr, 0x00, MODE_SENSE10_LEN); 307 | // Byte 2 is constant 0x06. I dont know how these commands are formatted. 308 | scsi->bfr[2] = 0x06; 309 | scsi->data_len = MODE_SENSE10_LEN; 310 | return SCSI_State_SendData; 311 | } 312 | 313 | static SCSI_State_t SCSI_RequestSense(SCSI_t * scsi, SCSI_CBW_t * cbw) 314 | { 315 | memset(scsi->bfr, 0x00, REQUEST_SENSE_LEN); 316 | 317 | scsi->bfr[0] = 0x70U; 318 | scsi->bfr[7] = REQUEST_SENSE_LEN - 6U; 319 | 320 | if ((scsi->sense.head != scsi->sense.tail)) 321 | { 322 | scsi->bfr[2] = scsi->sense.stack[scsi->sense.head].Skey; 323 | //scsi->bfr[12] // Leave ASCQ zero 324 | scsi->bfr[13] = scsi->sense.stack[scsi->sense.head].ASC; 325 | scsi->sense.head++; 326 | 327 | if (scsi->sense.head == SCSI_SENSE_DEPTH) 328 | { 329 | scsi->sense.head = 0U; 330 | } 331 | } 332 | scsi->data_len = REQUEST_SENSE_LEN; 333 | 334 | if (cbw->CB[4] <= REQUEST_SENSE_LEN) 335 | { 336 | scsi->data_len = cbw->CB[4]; 337 | } 338 | return SCSI_State_SendData; 339 | } 340 | 341 | SCSI_State_t SCSI_SenseCode(SCSI_t * scsi, uint8_t sKey, uint8_t ASC) 342 | { 343 | scsi->sense.stack[scsi->sense.tail].Skey = sKey; 344 | scsi->sense.stack[scsi->sense.tail].ASC = ASC; 345 | scsi->sense.tail++; 346 | if (scsi->sense.tail == SCSI_SENSE_DEPTH) 347 | { 348 | scsi->sense.tail = 0U; 349 | } 350 | return SCSI_State_Error; 351 | } 352 | 353 | static SCSI_State_t SCSI_StartStopUnit(SCSI_t * scsi, SCSI_CBW_t * cbw) 354 | { 355 | return SCSI_State_Ok; 356 | } 357 | 358 | static SCSI_State_t SCSI_Read10(SCSI_t * scsi, SCSI_CBW_t * cbw) 359 | { 360 | if ((cbw->bmFlags & 0x80U) != 0x80U) 361 | { 362 | return SCSI_SenseCode(scsi, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASQ_INVALID_CDB); 363 | } 364 | 365 | if (scsi->storage == NULL) 366 | { 367 | return SCSI_SenseCode(scsi, SCSI_SKEY_NOT_READY, SCSI_ASQ_MEDIUM_NOT_PRESENT); 368 | } 369 | 370 | scsi->block_addr = ((uint32_t)cbw->CB[2] << 24) 371 | | ((uint32_t)cbw->CB[3] << 16) 372 | | ((uint32_t)cbw->CB[4] << 8) 373 | | (uint32_t)cbw->CB[5]; 374 | 375 | scsi->block_len = ((uint32_t)cbw->CB[7] << 8) | (uint32_t)cbw->CB[8]; 376 | 377 | if (SCSI_CheckAddressRange(scsi, scsi->block_addr, scsi->block_len) != SCSI_State_Ok) 378 | { 379 | return SCSI_State_Error; 380 | } 381 | 382 | /* cases 4,5 : Hi <> Dn */ 383 | if (cbw->dDataLength != (scsi->block_len * SCSI_BLOCK_SIZE)) 384 | { 385 | return SCSI_SenseCode(scsi, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASQ_INVALID_CDB); 386 | } 387 | 388 | return SCSI_ProcessRead(scsi); 389 | } 390 | 391 | static SCSI_State_t SCSI_Write10(SCSI_t * scsi, SCSI_CBW_t * cbw) 392 | { 393 | if ((cbw->bmFlags & 0x80U) == 0x80U) 394 | { 395 | return SCSI_SenseCode(scsi, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASQ_INVALID_CDB); 396 | } 397 | 398 | if (scsi->storage == NULL) 399 | { 400 | return SCSI_SenseCode(scsi, SCSI_SKEY_NOT_READY, SCSI_ASQ_MEDIUM_NOT_PRESENT); 401 | } 402 | 403 | if (scsi->storage->write == NULL) 404 | { 405 | return SCSI_SenseCode(scsi, SCSI_SKEY_NOT_READY, SCSI_ASQ_WRITE_PROTECTED); 406 | } 407 | 408 | scsi->block_addr = ((uint32_t)cbw->CB[2] << 24) | 409 | ((uint32_t)cbw->CB[3] << 16) | 410 | ((uint32_t)cbw->CB[4] << 8) | 411 | (uint32_t)cbw->CB[5]; 412 | 413 | scsi->block_len = ((uint32_t)cbw->CB[7] << 8) | 414 | (uint32_t)cbw->CB[8]; 415 | 416 | // check if LBA address is in the right range 417 | if (SCSI_CheckAddressRange(scsi, scsi->block_addr, scsi->block_len) != SCSI_State_Ok) 418 | { 419 | return SCSI_State_Error; 420 | } 421 | 422 | if (cbw->dDataLength != (scsi->block_len * SCSI_BLOCK_SIZE)) 423 | { 424 | return SCSI_SenseCode(scsi, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASQ_INVALID_CDB); 425 | } 426 | 427 | scsi->data_len = SCSI_BLOCK_SIZE; 428 | return SCSI_State_DataOut; 429 | } 430 | 431 | static SCSI_State_t SCSI_Verify10(SCSI_t * scsi, SCSI_CBW_t * cbw) 432 | { 433 | if ((cbw->CB[1] & 0x02U) == 0x02U) 434 | { 435 | // Verify mode not supported 436 | return SCSI_SenseCode(scsi, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASQ_INVALID_FIELD_IN_COMMAND); 437 | } 438 | 439 | if (SCSI_CheckAddressRange(scsi, scsi->block_addr, scsi->block_len) < 0) 440 | { 441 | return SCSI_State_Error; 442 | } 443 | return SCSI_State_Ok; 444 | } 445 | 446 | static SCSI_State_t SCSI_CheckAddressRange(SCSI_t * scsi, uint32_t blk_offset, uint32_t blk_nbr) 447 | { 448 | if ((blk_offset + blk_nbr) > scsi->block_count) 449 | { 450 | return SCSI_SenseCode(scsi, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASQ_ADDRESS_OUT_OF_RANGE); 451 | } 452 | return SCSI_State_Ok; 453 | } 454 | 455 | static SCSI_State_t SCSI_ProcessRead(SCSI_t * scsi) 456 | { 457 | if (!scsi->storage->read(scsi->bfr, scsi->block_addr, 1)) 458 | { 459 | return SCSI_SenseCode(scsi, SCSI_SKEY_HARDWARE_ERROR, SCSI_ASQ_UNRECOVERED_READ_ERROR); 460 | } 461 | 462 | scsi->block_addr += 1; 463 | scsi->block_len -= 1; 464 | scsi->data_len = SCSI_BLOCK_SIZE; 465 | 466 | if (scsi->block_len == 0) 467 | { 468 | return SCSI_State_LastDataIn; 469 | } 470 | return SCSI_State_DataIn; 471 | } 472 | 473 | static SCSI_State_t SCSI_ProcessWrite(SCSI_t * scsi) 474 | { 475 | if (!scsi->storage->write(scsi->bfr, scsi->block_addr, 1)) 476 | { 477 | return SCSI_SenseCode(scsi, SCSI_SKEY_HARDWARE_ERROR, SCSI_ASQ_WRITE_FAULT); 478 | } 479 | 480 | scsi->block_addr += 1; 481 | scsi->block_len -= 1; 482 | 483 | if (scsi->block_len == 0) 484 | { 485 | return SCSI_State_Ok; 486 | } 487 | else 488 | { 489 | scsi->data_len = SCSI_BLOCK_SIZE; 490 | return SCSI_State_DataOut; 491 | } 492 | } 493 | 494 | -------------------------------------------------------------------------------- /tests/test_src/usb/USB_CTL.c: -------------------------------------------------------------------------------- 1 | 2 | #include "USB_CTL.h" 3 | #ifdef USB_ENABLE 4 | 5 | #include "USB_Defs.h" 6 | #include "USB_Class.h" 7 | #include "USB_EP.h" 8 | #include "USB_PCD.h" 9 | 10 | 11 | /* 12 | * PRIVATE DEFINITIONS 13 | */ 14 | 15 | #ifndef USB_CLASS_CLASSID 16 | // Most classes are Interface defined, and so these should all be zero. 17 | #define USB_CLASS_CLASSID 0x00 18 | #define USB_CLASS_SUBCLASSID 0x00 19 | #define USB_CLASS_PROTOCOLID 0x00 20 | #endif 21 | 22 | #define CTL_IN_EP 0x80 23 | #define CTL_OUT_EP 0x00 24 | 25 | #define CTL_EP_SIZE USB_MAX_EP0_SIZE 26 | 27 | typedef enum { 28 | USB_STATE_DEFAULT, 29 | USB_STATE_ADDRESSED, 30 | USB_STATE_CONFIGURED, 31 | USB_STATE_SUSPENDED 32 | } USB_State_t; 33 | 34 | typedef enum { 35 | CTL_STATE_IDLE, 36 | CTL_STATE_SETUP, 37 | CTL_STATE_DATA_IN, 38 | CTL_STATE_DATA_OUT, 39 | CTL_STATE_STATUS_IN, 40 | CTL_STATE_STATUS_OUT, 41 | CTL_STATE_STALL, 42 | } CTL_State_t; 43 | 44 | /* 45 | * PRIVATE TYPES 46 | */ 47 | 48 | /* 49 | * PUBLIC TYPES 50 | */ 51 | 52 | /* 53 | * PRIVATE PROTOTYPES 54 | */ 55 | 56 | static void USB_CTL_EndpointRequest(USB_SetupRequest_t *req); 57 | static void USB_CTL_DeviceRequest(USB_SetupRequest_t *req); 58 | static void USB_CTL_InterfaceRequest(USB_SetupRequest_t *req); 59 | 60 | static void USB_CTL_SetAddress(USB_SetupRequest_t * req); 61 | static void USB_CTL_SetFeature(USB_SetupRequest_t *req); 62 | static void USB_CTL_ClearFeature(USB_SetupRequest_t *req); 63 | static void USB_CTL_GetConfig(USB_SetupRequest_t *req); 64 | static void USB_CTL_SetConfig(USB_SetupRequest_t *req); 65 | static void USB_CTL_GetStatus(USB_SetupRequest_t *req); 66 | static void USB_CTL_GetDescriptor(USB_SetupRequest_t *req); 67 | 68 | static uint16_t USB_CTL_GetLangIdDescriptor(uint8_t * data); 69 | static uint16_t USB_CTL_GetStrDescriptor(uint8_t * data, const char * str); 70 | static uint16_t USB_CTL_GetSerialDescriptor(uint8_t * data); 71 | 72 | static void USB_CTL_SendStatus(void); 73 | static void USB_CTL_ReceiveStatus(void); 74 | static void USB_CTL_Error(void); 75 | 76 | static void USB_CTL_DataOut(uint32_t count); 77 | static void USB_CTL_DataIn(uint32_t count); 78 | 79 | 80 | /* 81 | * PRIVATE VARIABLES 82 | */ 83 | 84 | #define CTL_BUFFER_SIZE (MAX((USB_MAX_STRING_SIZE+1)*2, CTL_EP_SIZE)) 85 | 86 | static struct { 87 | uint8_t address; 88 | uint8_t class_config; 89 | uint8_t usb_state; 90 | bool remote_wakeup; 91 | uint8_t ctl_state; 92 | uint16_t ctl_len; 93 | uint8_t buffer[CTL_BUFFER_SIZE]; 94 | } gCTL; 95 | 96 | __ALIGNED(4) const uint8_t cUsbDeviceDescriptor[USB_LEN_DEV_DESC] = 97 | { 98 | USB_LEN_DEV_DESC, // bLength 99 | USB_DESC_TYPE_DEVICE, // bDescriptorType 100 | 0x00, // bcdUSB 101 | 0x02, 102 | USB_CLASS_CLASSID, // bDeviceClass 103 | USB_CLASS_SUBCLASSID, // bDeviceSubClass 104 | USB_CLASS_PROTOCOLID, // bDeviceProtocol 105 | CTL_EP_SIZE, // bMaxPacketSize 106 | LOBYTE(USB_VID), // idVendor 107 | HIBYTE(USB_VID), // idVendor 108 | LOBYTE(USB_PID), // idProduct 109 | HIBYTE(USB_PID), // idProduct 110 | 0x00, // bcdDevice rel. 2.00 111 | 0x02, 112 | USB_IDX_MFC_STR, // Index of manufacturer string 113 | USB_IDX_PRODUCT_STR, // Index of product string 114 | USB_IDX_SERIAL_STR, // Index of serial number string 115 | USB_MAX_NUM_CONFIGURATION // bNumConfigurations 116 | }; 117 | 118 | /* 119 | * PUBLIC FUNCTIONS 120 | */ 121 | 122 | 123 | void USB_CTL_Init(void) 124 | { 125 | USB_EP_Open(CTL_IN_EP, USB_EP_TYPE_CTRL, CTL_EP_SIZE, USB_CTL_DataIn); 126 | USB_EP_Open(CTL_OUT_EP, USB_EP_TYPE_CTRL, CTL_EP_SIZE, USB_CTL_DataOut); 127 | gCTL.address = 0; 128 | gCTL.class_config = 0; 129 | gCTL.usb_state = USB_STATE_DEFAULT; 130 | gCTL.remote_wakeup = false; 131 | gCTL.ctl_state = CTL_STATE_IDLE; 132 | } 133 | 134 | void USB_CTL_Deinit(void) 135 | { 136 | // Dont bother closing the CTL EP's 137 | if (gCTL.class_config != 0) 138 | { 139 | gCTL.class_config = 0; 140 | USB_CLASS_DEINIT(); 141 | } 142 | } 143 | 144 | void USB_CTL_HandleSetup(uint8_t * data) 145 | { 146 | USB_SetupRequest_t req; 147 | req.bmRequest = *(data); 148 | req.bRequest = *(data + 1U); 149 | req.wValue = SWAPBYTE(data + 2U); 150 | req.wIndex = SWAPBYTE(data + 4U); 151 | req.wLength = SWAPBYTE(data + 6U); 152 | 153 | gCTL.ctl_state = CTL_STATE_SETUP; 154 | gCTL.ctl_len = req.wLength; 155 | 156 | switch (req.bmRequest & 0x1F) 157 | { 158 | case USB_REQ_RECIPIENT_DEVICE: 159 | USB_CTL_DeviceRequest(&req); 160 | break; 161 | case USB_REQ_RECIPIENT_INTERFACE: 162 | USB_CTL_InterfaceRequest(&req); 163 | break; 164 | case USB_REQ_RECIPIENT_ENDPOINT: 165 | USB_CTL_EndpointRequest(&req); 166 | break; 167 | default: 168 | USB_EP_Stall(req.bmRequest & 0x80); 169 | break; 170 | } 171 | } 172 | 173 | void USB_CTL_Send(uint8_t * data, uint16_t size) 174 | { 175 | gCTL.ctl_state = CTL_STATE_DATA_IN; 176 | USB_EP_Write(CTL_IN_EP, data, size); 177 | } 178 | 179 | void USB_CTL_Receive(uint8_t * data, uint16_t size) 180 | { 181 | gCTL.ctl_state = CTL_STATE_DATA_OUT; 182 | USB_EP_Read(CTL_OUT_EP, data, size); 183 | } 184 | 185 | /* 186 | * PRIVATE FUNCTIONS 187 | */ 188 | 189 | 190 | static void USB_CTL_ReceiveStatus(void) 191 | { 192 | gCTL.ctl_state = CTL_STATE_STATUS_OUT; 193 | USB_EP_Read(CTL_OUT_EP, NULL, 0); 194 | } 195 | 196 | static void USB_CTL_SendStatus(void) 197 | { 198 | gCTL.ctl_state = CTL_STATE_STATUS_IN; 199 | USB_EP_Write(0x00U, NULL, 0U); 200 | } 201 | 202 | static void USB_CTL_EndpointRequest(USB_SetupRequest_t *req) 203 | { 204 | uint8_t endpoint = LOBYTE(req->wIndex); 205 | 206 | switch (req->bmRequest & USB_REQ_TYPE_MASK) 207 | { 208 | #ifdef USB_CLASS_CUSTOM_SETUP 209 | case USB_REQ_TYPE_CLASS: 210 | case USB_REQ_TYPE_VENDOR: 211 | USB_CLASS_SETUP(req); 212 | return; 213 | #endif 214 | case USB_REQ_TYPE_STANDARD: 215 | switch (req->bRequest) 216 | { 217 | case USB_REQ_SET_FEATURE: 218 | switch (gCTL.usb_state) 219 | { 220 | case USB_STATE_ADDRESSED: 221 | if ((endpoint != CTL_OUT_EP) && (endpoint != CTL_IN_EP)) 222 | { 223 | USB_EP_Stall(endpoint); 224 | USB_EP_Stall(CTL_IN_EP); 225 | return; 226 | } 227 | break; 228 | case USB_STATE_CONFIGURED: 229 | if (req->wValue == USB_FEATURE_EP_HALT) 230 | { 231 | if ((endpoint != CTL_OUT_EP) && (endpoint != CTL_IN_EP) && (req->wLength == 0x00U)) 232 | { 233 | USB_EP_Stall(endpoint); 234 | } 235 | } 236 | USB_CTL_SendStatus(); 237 | return; 238 | } 239 | break; 240 | case USB_REQ_CLEAR_FEATURE: 241 | switch (gCTL.usb_state) 242 | { 243 | case USB_STATE_ADDRESSED: 244 | if ((endpoint & 0x7FU) != 0x00U) 245 | { 246 | USB_EP_Stall(endpoint); 247 | USB_EP_Stall(CTL_IN_EP); 248 | } 249 | break; 250 | case USB_STATE_CONFIGURED: 251 | if (req->wValue == USB_FEATURE_EP_HALT) 252 | { 253 | if ((endpoint & 0x7FU) != 0x00U) 254 | { 255 | USB_EP_Destall(endpoint); 256 | } 257 | USB_CTL_SendStatus(); 258 | return; 259 | } 260 | break; 261 | } 262 | break; 263 | case USB_REQ_GET_STATUS: 264 | switch (gCTL.usb_state) 265 | { 266 | case USB_STATE_ADDRESSED: 267 | case USB_STATE_CONFIGURED: 268 | if (USB_EP_IsOpen(endpoint)) 269 | { 270 | uint16_t status = USB_EP_IsStalled(endpoint) ? 0x0001 : 0x0000; 271 | USB_CTL_Send((uint8_t *)&status, 2); 272 | return; 273 | } 274 | break; 275 | } 276 | break; 277 | } 278 | break; 279 | } 280 | USB_CTL_Error(); 281 | } 282 | 283 | /* 284 | static void USB_CTL_StandardClassRequest(USB_SetupRequest_t *req) 285 | { 286 | if (gCTL.usb_state == USB_STATE_CONFIGURED) 287 | { 288 | switch (req->bRequest) 289 | { 290 | case USB_REQ_GET_STATUS: 291 | { 292 | // status is always 0 for classes 293 | uint16_t status_info = 0; 294 | USB_CTL_Send((uint8_t *)&status_info, 2U); 295 | return; 296 | } 297 | case USB_REQ_GET_INTERFACE: 298 | { 299 | // Alternate interfaces not supported. 300 | uint8_t ifalt = 0; 301 | USB_CTL_Send(&ifalt, 1); 302 | return; 303 | } 304 | case USB_REQ_SET_INTERFACE: 305 | return; 306 | } 307 | } 308 | USB_CTL_Error(); 309 | } 310 | */ 311 | 312 | static void USB_CTL_DeviceRequest(USB_SetupRequest_t *req) 313 | { 314 | switch (req->bmRequest & USB_REQ_TYPE_MASK) 315 | { 316 | #ifdef USB_CLASS_CUSTOM_SETUP 317 | case USB_REQ_TYPE_CLASS: 318 | case USB_REQ_TYPE_VENDOR: 319 | USB_CLASS_SETUP(req); 320 | return; 321 | #endif 322 | case USB_REQ_TYPE_STANDARD: 323 | switch (req->bRequest) 324 | { 325 | case USB_REQ_GET_DESCRIPTOR: 326 | USB_CTL_GetDescriptor(req); 327 | return; 328 | case USB_REQ_SET_ADDRESS: 329 | USB_CTL_SetAddress(req); 330 | return; 331 | case USB_REQ_SET_CONFIGURATION: 332 | USB_CTL_SetConfig(req); 333 | return; 334 | case USB_REQ_GET_CONFIGURATION: 335 | USB_CTL_GetConfig(req); 336 | return; 337 | case USB_REQ_GET_STATUS: 338 | USB_CTL_GetStatus(req); 339 | return; 340 | case USB_REQ_SET_FEATURE: 341 | USB_CTL_SetFeature(req); 342 | return; 343 | case USB_REQ_CLEAR_FEATURE: 344 | USB_CTL_ClearFeature(req); 345 | return; 346 | } 347 | break; 348 | } 349 | USB_CTL_Error(); 350 | } 351 | 352 | 353 | static void USB_CTL_SetFeature(USB_SetupRequest_t * req) 354 | { 355 | if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) 356 | { 357 | // Support for issuing a remote wakeup is missing. 358 | // USB_CNTR_RESUME should be set when resume is requested. 359 | gCTL.remote_wakeup = true; 360 | USB_CTL_SendStatus(); 361 | } 362 | } 363 | 364 | static void USB_CTL_ClearFeature(USB_SetupRequest_t * req) 365 | { 366 | switch (gCTL.usb_state) 367 | { 368 | case USB_STATE_DEFAULT: 369 | case USB_STATE_ADDRESSED: 370 | case USB_STATE_CONFIGURED: 371 | if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) 372 | { 373 | gCTL.remote_wakeup = false; 374 | USB_CTL_SendStatus(); 375 | return; 376 | } 377 | } 378 | USB_CTL_Error(); 379 | } 380 | 381 | static void USB_CTL_SetAddress(USB_SetupRequest_t * req) 382 | { 383 | if ((req->wIndex == 0) && (req->wLength == 0) && (req->wValue < 128)) 384 | { 385 | if (gCTL.usb_state != USB_STATE_CONFIGURED) 386 | { 387 | uint8_t address = (uint8_t)(req->wValue) & 0x7FU; 388 | gCTL.usb_state = (address != 0) ? USB_STATE_ADDRESSED : USB_STATE_DEFAULT; 389 | gCTL.address = address; 390 | USB_CTL_SendStatus(); 391 | return; 392 | } 393 | } 394 | USB_CTL_Error(); 395 | } 396 | 397 | static void USB_CTL_SetConfig(USB_SetupRequest_t * req) 398 | { 399 | uint8_t config = (uint8_t)(req->wValue); 400 | if (config <= USB_MAX_NUM_CONFIGURATION) 401 | { 402 | if (gCTL.class_config != 0) 403 | { 404 | gCTL.class_config = 0; 405 | USB_CLASS_DEINIT(); 406 | } 407 | 408 | switch (gCTL.usb_state) 409 | { 410 | case USB_STATE_ADDRESSED: 411 | case USB_STATE_CONFIGURED: 412 | if (config == 0) 413 | { 414 | gCTL.usb_state = USB_STATE_ADDRESSED; 415 | } 416 | else 417 | { 418 | gCTL.usb_state = USB_STATE_CONFIGURED; 419 | gCTL.class_config = config; 420 | USB_CLASS_INIT(config); 421 | } 422 | USB_CTL_SendStatus(); 423 | return; 424 | } 425 | } 426 | USB_CTL_Error(); 427 | } 428 | 429 | static void USB_CTL_GetConfig(USB_SetupRequest_t * req) 430 | { 431 | if (req->wLength == 1) 432 | { 433 | switch (gCTL.usb_state) 434 | { 435 | case USB_STATE_DEFAULT: 436 | case USB_STATE_ADDRESSED: 437 | case USB_STATE_CONFIGURED: 438 | USB_CTL_Send(&gCTL.class_config, 1); 439 | return; 440 | } 441 | } 442 | USB_CTL_Error(); 443 | } 444 | 445 | static void USB_CTL_GetStatus(USB_SetupRequest_t * req) 446 | { 447 | switch (gCTL.usb_state) 448 | { 449 | case USB_STATE_DEFAULT: 450 | case USB_STATE_ADDRESSED: 451 | case USB_STATE_CONFIGURED: 452 | if (req->wLength == 0x2U) 453 | { 454 | #ifdef USB_SELF_POWERED 455 | uint16_t status = USB_CONFIG_SELF_POWERED; 456 | #else 457 | uint16_t status = 0; 458 | #endif 459 | if (gCTL.remote_wakeup) 460 | { 461 | status |= USB_CONFIG_REMOTE_WAKEUP; 462 | } 463 | USB_CTL_Send((uint8_t *)&status, 2); 464 | return; 465 | } 466 | } 467 | USB_CTL_Error(); 468 | } 469 | 470 | static void USB_CTL_InterfaceRequest(USB_SetupRequest_t * req) 471 | { 472 | switch (req->bmRequest & USB_REQ_TYPE_MASK) 473 | { 474 | case USB_REQ_TYPE_CLASS: 475 | case USB_REQ_TYPE_VENDOR: 476 | case USB_REQ_TYPE_STANDARD: 477 | switch (gCTL.usb_state) 478 | { 479 | case USB_STATE_DEFAULT: 480 | case USB_STATE_ADDRESSED: 481 | case USB_STATE_CONFIGURED: 482 | if (LOBYTE(req->wIndex) < USB_INTERFACES) 483 | { 484 | USB_CLASS_SETUP(req); 485 | if ((req->wLength == 0U)) 486 | { 487 | USB_CTL_SendStatus(); 488 | } 489 | return; 490 | } 491 | break; 492 | } 493 | break; 494 | } 495 | USB_CTL_Error(); 496 | } 497 | 498 | 499 | static void USB_CTL_GetDescriptor(USB_SetupRequest_t * req) 500 | { 501 | uint16_t len = 0; 502 | uint8_t *data = NULL; 503 | 504 | switch (HIBYTE(req->wValue)) 505 | { 506 | #ifdef USB_USE_LPM 507 | case USB_DESC_TYPE_BOS: 508 | #error "This BOS descriptor must be implemented for LPM mode" 509 | break; 510 | #endif 511 | case USB_DESC_TYPE_DEVICE: 512 | data = (uint8_t *)cUsbDeviceDescriptor; 513 | len = sizeof(cUsbDeviceDescriptor); 514 | break; 515 | 516 | case USB_DESC_TYPE_CONFIGURATION: 517 | data = (uint8_t *)USB_CLASS_DEVICE_DESCRIPTOR; 518 | len = sizeof(USB_CLASS_DEVICE_DESCRIPTOR); 519 | break; 520 | 521 | case USB_DESC_TYPE_STRING: 522 | // These descriptors will be copied into the CTL buffer. 523 | data = gCTL.buffer; 524 | switch ((uint8_t)(req->wValue)) 525 | { 526 | case USB_IDX_LANGID_STR: 527 | len = USB_CTL_GetLangIdDescriptor(data); 528 | break; 529 | case USB_IDX_MFC_STR: 530 | len = USB_CTL_GetStrDescriptor(data, USB_MANUFACTURER_STRING); 531 | break; 532 | case USB_IDX_PRODUCT_STR: 533 | len = USB_CTL_GetStrDescriptor(data, USB_PRODUCT_STRING); 534 | break; 535 | case USB_IDX_SERIAL_STR: 536 | len = USB_CTL_GetSerialDescriptor(data); 537 | break; 538 | case USB_IDX_CONFIG_STR: 539 | len = USB_CTL_GetStrDescriptor(data, USB_CONFIGURATION_STRING); 540 | break; 541 | case USB_IDX_INTERFACE_STR: 542 | len = USB_CTL_GetStrDescriptor(data, USB_INTERFACE_STRING); 543 | break; 544 | } 545 | break; 546 | 547 | case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: 548 | case USB_DESC_TYPE_DEVICE_QUALIFIER: 549 | // We do not support full speed mode, so stalling on these requests is valid 550 | break; 551 | } 552 | 553 | if (len == 0) 554 | { 555 | USB_CTL_Error(); 556 | } 557 | else if (req->wLength == 0) 558 | { 559 | // No data was requested. 560 | USB_CTL_SendStatus(); 561 | } 562 | else 563 | { 564 | // Note: a partial descriptor may be requested 565 | USB_CTL_Send(data, MIN(len, req->wLength)); 566 | } 567 | } 568 | 569 | static uint16_t USB_CTL_GetStrDescriptor(uint8_t * data, const char * str) 570 | { 571 | uint16_t i = 2; 572 | while (*str != 0) 573 | { 574 | data[i++] = *str++; 575 | data[i++] = 0; 576 | } 577 | data[0] = i; 578 | data[1] = USB_DESC_TYPE_STRING; 579 | return i; 580 | } 581 | 582 | static void USB_CTL_IntToUnicode(uint32_t value, uint8_t * data, uint32_t size) 583 | { 584 | while (size--) 585 | { 586 | uint32_t v = value >> 28; 587 | value <<= 4; 588 | *data++ = (v < 0x0A) ? v + '0' : v + ('A' - 10); 589 | *data++ = 0; 590 | } 591 | } 592 | 593 | static uint16_t USB_CTL_GetSerialDescriptor(uint8_t * data) 594 | { 595 | uint32_t s0 = *((uint32_t*)(UID_BASE + 0)); 596 | uint32_t s1 = *((uint32_t*)(UID_BASE + 4)); 597 | uint32_t s2 = *((uint32_t*)(UID_BASE + 8)); 598 | s0 += s2; 599 | 600 | // We are slamming our 96bit (12) UID into a 6 byte string. 601 | // Is this a good idea?? 602 | // One byte goes to 2 unicode characters 0x1F => { 0, '1', 0, 'F' } 603 | 604 | data[0] = 24 + 2; 605 | data[1] = USB_DESC_TYPE_STRING; 606 | USB_CTL_IntToUnicode(s0, data + 2, 8); 607 | USB_CTL_IntToUnicode(s1, data + 18, 4); 608 | return 24 + 2; 609 | } 610 | 611 | static uint16_t USB_CTL_GetLangIdDescriptor(uint8_t * data) 612 | { 613 | data[0] = 4; 614 | data[1] = USB_DESC_TYPE_STRING; 615 | data[2] = LOBYTE(USB_LANGID); 616 | data[3] = HIBYTE(USB_LANGID); 617 | return 4; 618 | } 619 | 620 | static void USB_CTL_Error(void) 621 | { 622 | USB_EP_Stall(CTL_IN_EP); 623 | USB_EP_Stall(CTL_OUT_EP); 624 | } 625 | 626 | 627 | static void USB_CTL_DataOut(uint32_t count) 628 | { 629 | switch (gCTL.ctl_state) 630 | { 631 | case CTL_STATE_DATA_OUT: 632 | #ifdef USB_CLASS_CTL_RXREADY 633 | if (gCTL.usb_state == USB_STATE_CONFIGURED) 634 | { 635 | USB_CLASS_CTL_RXREADY(); 636 | } 637 | #endif 638 | USB_CTL_SendStatus(); 639 | break; 640 | case CTL_STATE_STATUS_OUT: 641 | if (gCTL.ctl_state == USB_STATE_CONFIGURED) 642 | { 643 | // STATUS PHASE completed, update ep0_state to idle 644 | gCTL.ctl_state = CTL_STATE_IDLE; 645 | USB_EP_Stall(CTL_OUT_EP); 646 | } 647 | break; 648 | } 649 | 650 | USB_EP_Read(CTL_OUT_EP, gCTL.buffer, CTL_EP_SIZE); 651 | } 652 | 653 | static void USB_CTL_DataIn(uint32_t count) 654 | { 655 | switch (gCTL.ctl_state) 656 | { 657 | case CTL_STATE_DATA_IN: 658 | #ifdef USB_CLASS_CTL_TXDONE 659 | if (gCTL.usb_state == USB_STATE_CONFIGURED) 660 | { 661 | USB_CLASS_CTL_TXDONE(); 662 | } 663 | #endif 664 | USB_EP_Stall(CTL_IN_EP); 665 | USB_CTL_ReceiveStatus(); 666 | break; 667 | case CTL_STATE_STATUS_IN: 668 | case CTL_STATE_IDLE: 669 | USB_EP_Stall(CTL_IN_EP); 670 | break; 671 | } 672 | 673 | if (gCTL.address != 0) 674 | { 675 | USB_PCD_SetAddress(gCTL.address); 676 | gCTL.address = 0; 677 | } 678 | } 679 | 680 | /* 681 | * INTERRUPT ROUTINES 682 | */ 683 | 684 | #endif //USB_ENABLE 685 | -------------------------------------------------------------------------------- /tests/test_src/usb/USB_EP.c: -------------------------------------------------------------------------------- 1 | 2 | #include "USB_EP.h" 3 | #ifdef USB_ENABLE 4 | 5 | #include "USB_CTL.h" 6 | #include "USB_PCD.h" 7 | #include "USB_Defs.h" 8 | #include "USB_Class.h" 9 | 10 | /* 11 | * PRIVATE DEFINITIONS 12 | */ 13 | 14 | #define BTABLE_SIZE (USB_ENDPOINTS * 8) 15 | 16 | #define PMA_SIZE 1024 17 | #define PMA_BASE (((uint32_t)USB) + 0x400) 18 | 19 | /* 20 | * PRIVATE TYPES 21 | */ 22 | 23 | typedef struct { 24 | uint8_t num; 25 | bool is_in; 26 | bool is_stall; 27 | uint8_t type; 28 | uint16_t pmaadress; 29 | #ifdef USB_USE_DOUBLEBUFFER 30 | uint16_t pmaaddr0; 31 | uint16_t pmaaddr1; 32 | uint32_t xfer_len_db; 33 | bool xfer_fill_db; 34 | uint8_t doublebuffer; 35 | #endif 36 | uint32_t maxpacket; 37 | uint8_t * xfer_buff; 38 | uint32_t xfer_len; 39 | uint32_t xfer_count; 40 | USB_EP_Callback_t callback; 41 | } USB_EP_t; 42 | 43 | /* 44 | * PRIVATE PROTOTYPES 45 | */ 46 | 47 | static uint16_t USB_PMA_Alloc(uint16_t size); 48 | static void USB_PMA_Write(uint16_t address, uint8_t * data, uint16_t count); 49 | static void USB_PMA_Read(uint16_t address, uint8_t * data, uint16_t count); 50 | static void USB_EP_Activate(USB_EP_t *ep); 51 | static void USB_EP_Deactivate(USB_EP_t *ep); 52 | 53 | static USB_EP_t * USB_EP_GetEP(uint8_t endpoint); 54 | static void USB_EP_StartIn(USB_EP_t *ep); 55 | static void USB_EP_StartOut(USB_EP_t *ep); 56 | 57 | #ifdef USE_EP_DOUBLEBUFFER 58 | static uint16_t USB_EP_ReceiveDB(USB_EP_t *ep, uint16_t wEPVal); 59 | static void USB_EP_TransmitDB(USB_EP_t *ep, uint16_t wEPVal); 60 | #endif //USE_EP_DOUBLEBUFFER 61 | 62 | /* 63 | * PRIVATE VARIABLES 64 | */ 65 | 66 | static struct { 67 | uint16_t pma_head; 68 | USB_EP_t in_ep[USB_ENDPOINTS]; 69 | USB_EP_t out_ep[USB_ENDPOINTS]; 70 | }gEP; 71 | 72 | /* 73 | * PUBLIC FUNCTIONS 74 | */ 75 | 76 | void USB_EP_Init(void) 77 | { 78 | gEP.pma_head = BTABLE_SIZE; 79 | 80 | for (uint32_t i = 0U; i < USB_ENDPOINTS; i++) 81 | { 82 | USB_EP_t * ep = &gEP.in_ep[i]; 83 | ep->is_in = true; 84 | ep->num = i; 85 | ep->type = USB_EP_TYPE_NONE; 86 | ep->maxpacket = 0; 87 | ep->xfer_buff = 0; 88 | ep->xfer_len = 0; 89 | } 90 | for (uint32_t i = 0U; i < USB_ENDPOINTS; i++) 91 | { 92 | USB_EP_t * ep = &gEP.out_ep[i]; 93 | ep->is_in = false; 94 | ep->num = i; 95 | ep->type = USB_EP_TYPE_NONE; 96 | ep->maxpacket = 0; 97 | ep->xfer_buff = 0; 98 | ep->xfer_len = 0; 99 | } 100 | } 101 | 102 | void USB_EP_Reset(void) 103 | { 104 | gEP.pma_head = BTABLE_SIZE; 105 | } 106 | 107 | void USB_EP_Deinit(void) 108 | { 109 | 110 | } 111 | 112 | void USB_EP_Open(uint8_t endpoint, uint8_t type, uint16_t size, USB_EP_Callback_t callback) 113 | { 114 | USB_EP_t * ep = USB_EP_GetEP(endpoint); 115 | ep->maxpacket = size; 116 | ep->type = type; 117 | ep->callback = callback; 118 | #ifdef USE_EP_DOUBLEBUFFER 119 | if (doublebuffer) 120 | { 121 | ep->doublebuffer = 1; 122 | ep->pmaaddr0 = USB_PMA_Alloc(size); 123 | ep->pmaaddr1 = USB_PMA_Alloc(size); 124 | } 125 | else 126 | { 127 | ep->pmaadress = USB_PMA_Alloc(size); 128 | } 129 | #else // USE_EP_DOUBLEBUFFER 130 | ep->pmaadress = USB_PMA_Alloc(size); 131 | #endif 132 | USB_EP_Activate(ep); 133 | } 134 | 135 | void USB_EP_Close(uint8_t endpoint) 136 | { 137 | USB_EP_t * ep = USB_EP_GetEP(endpoint); 138 | ep->type = USB_EP_TYPE_NONE; 139 | USB_EP_Deactivate(ep); 140 | } 141 | 142 | bool USB_EP_IsOpen(uint8_t endpoint) 143 | { 144 | USB_EP_t * ep = USB_EP_GetEP(endpoint); 145 | return ep->type != USB_EP_TYPE_NONE; 146 | } 147 | 148 | void USB_EP_Read(uint8_t endpoint, uint8_t * data, uint32_t count) 149 | { 150 | USB_EP_t * ep = &gEP.out_ep[endpoint & EP_ADDR_MSK]; 151 | ep->xfer_buff = data; 152 | ep->xfer_len = count; 153 | ep->xfer_count = 0; 154 | USB_EP_StartOut(ep); 155 | } 156 | 157 | void USB_EP_Write(uint8_t endpoint, const uint8_t * data, uint32_t count) 158 | { 159 | USB_EP_t * ep = &gEP.in_ep[endpoint & EP_ADDR_MSK]; 160 | ep->xfer_buff = (uint8_t *)data; 161 | ep->xfer_len = count; 162 | #ifdef USB_USE_DOUBLEBUFFER 163 | ep->xfer_fill_db = 1; 164 | ep->xfer_len_db = count; 165 | #endif 166 | ep->xfer_count = 0; 167 | USB_EP_StartIn(ep); 168 | } 169 | 170 | void USB_EP_WriteZLP(uint8_t endpoint) 171 | { 172 | uint8_t epnum = endpoint & EP_ADDR_MSK; 173 | PCD_SET_EP_TX_CNT(USB, epnum, 0); 174 | PCD_SET_EP_TX_STATUS(USB, epnum, USB_EP_TX_VALID); 175 | } 176 | 177 | void USB_EP_Stall(uint8_t endpoint) 178 | { 179 | USB_EP_t * ep = USB_EP_GetEP(endpoint); 180 | ep->is_stall = true; 181 | if (ep->is_in) 182 | { 183 | PCD_SET_EP_TX_STATUS(USB, ep->num, USB_EP_TX_STALL); 184 | } 185 | else 186 | { 187 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_STALL); 188 | } 189 | } 190 | 191 | void USB_EP_Destall(uint8_t endpoint) 192 | { 193 | USB_EP_t *ep = USB_EP_GetEP(endpoint); 194 | ep->is_stall = false; 195 | #ifdef USB_USE_DOUBLEBUFFER 196 | if (!ep->doublebuffer) 197 | #endif 198 | { 199 | if (ep->is_in) 200 | { 201 | PCD_CLEAR_TX_DTOG(USB, ep->num); 202 | if (ep->type != USB_EP_TYPE_ISOC) 203 | { 204 | PCD_SET_EP_TX_STATUS(USB, ep->num, USB_EP_TX_NAK); 205 | } 206 | } 207 | else 208 | { 209 | PCD_CLEAR_RX_DTOG(USB, ep->num); 210 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_VALID); 211 | } 212 | } 213 | } 214 | 215 | bool USB_EP_IsStalled(uint8_t endpoint) 216 | { 217 | USB_EP_t * ep = USB_EP_GetEP(endpoint); 218 | return ep->is_stall; 219 | } 220 | 221 | /* 222 | * PRIVATE FUNCTIONS 223 | */ 224 | 225 | static USB_EP_t * USB_EP_GetEP(uint8_t endpoint) 226 | { 227 | if (endpoint & 0x80U) 228 | { 229 | return &gEP.in_ep[endpoint & EP_ADDR_MSK]; 230 | } 231 | else 232 | { 233 | return &gEP.out_ep[endpoint & EP_ADDR_MSK]; 234 | } 235 | } 236 | 237 | static uint16_t USB_PMA_Alloc(uint16_t size) 238 | { 239 | uint16_t head = gEP.pma_head; 240 | gEP.pma_head += size; 241 | if (gEP.pma_head > PMA_SIZE) 242 | { 243 | // TODO: handle this better. 244 | __BKPT(); 245 | } 246 | return head; 247 | } 248 | 249 | static void USB_PMA_Write(uint16_t address, uint8_t * data, uint16_t count) 250 | { 251 | volatile uint16_t * pma = (volatile uint16_t *)(PMA_BASE + ((uint32_t)address * PMA_ACCESS)); 252 | uint32_t words = (count + 1) / 2; 253 | while(words--) 254 | { 255 | uint32_t b1 = *data++; 256 | uint32_t b2 = *data++; 257 | *pma = b1 | (b2 << 8); 258 | pma += PMA_ACCESS; 259 | } 260 | } 261 | 262 | static void USB_PMA_Read(uint16_t address, uint8_t * data, uint16_t count) 263 | { 264 | volatile uint16_t * pma = (volatile uint16_t *)(PMA_BASE + ((uint32_t)address * PMA_ACCESS)); 265 | uint32_t words = count / 2; 266 | 267 | while (words--) 268 | { 269 | uint32_t word = *pma; 270 | pma += PMA_ACCESS; 271 | *data++ = (uint8_t)word; 272 | *data++ = (uint8_t)(word >> 8); 273 | } 274 | 275 | if (count & 0x01) 276 | { 277 | uint32_t word = *pma; 278 | *data = (uint8_t)word; 279 | } 280 | } 281 | 282 | static void USB_EP_Activate(USB_EP_t *ep) 283 | { 284 | uint16_t epReg = PCD_GET_ENDPOINT(USB, ep->num) & USB_EP_T_MASK; 285 | 286 | switch (ep->type) 287 | { 288 | case USB_EP_TYPE_CTRL: 289 | epReg |= USB_EP_CONTROL; 290 | break; 291 | case USB_EP_TYPE_BULK: 292 | epReg |= USB_EP_BULK; 293 | break; 294 | case USB_EP_TYPE_INTR: 295 | epReg |= USB_EP_INTERRUPT; 296 | break; 297 | case USB_EP_TYPE_ISOC: 298 | epReg |= USB_EP_ISOCHRONOUS; 299 | break; 300 | } 301 | 302 | PCD_SET_ENDPOINT(USB, ep->num, (epReg | USB_EP_CTR_RX | USB_EP_CTR_TX)); 303 | PCD_SET_EP_ADDRESS(USB, ep->num, ep->num); 304 | 305 | #ifdef USE_EP_DOUBLEBUFFER 306 | if (ep->doublebuffer) 307 | { 308 | PCD_SET_EP_DBUF(USB, ep->num); 309 | PCD_SET_EP_DBUF_ADDR(USB, ep->num, ep->pmaaddr0, ep->pmaaddr1); 310 | PCD_CLEAR_RX_DTOG(USB, ep->num); 311 | PCD_CLEAR_TX_DTOG(USB, ep->num); 312 | 313 | if (ep->is_in) 314 | { 315 | if (ep->type != EP_TYPE_ISOC) 316 | { 317 | PCD_SET_EP_TX_STATUS(USB, ep->num, USB_EP_TX_NAK); 318 | } 319 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_DIS); 320 | } 321 | else 322 | { 323 | // Clear the data toggle bits for the endpoint IN/OUT 324 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_VALID); 325 | PCD_SET_EP_TX_STATUS(USB, ep->num, USB_EP_TX_DIS); 326 | } 327 | return 328 | } 329 | #endif //USE_EP_DOUBLEBUFFER 330 | if (ep->is_in) 331 | { 332 | PCD_SET_EP_TX_ADDRESS(USB, ep->num, ep->pmaadress); 333 | PCD_CLEAR_TX_DTOG(USB, ep->num); 334 | // Isochronos should leave their TX EP disabled. 335 | if (ep->type != USB_EP_TYPE_ISOC) 336 | { 337 | PCD_SET_EP_TX_STATUS(USB, ep->num, USB_EP_TX_NAK); 338 | } 339 | } 340 | else 341 | { 342 | PCD_SET_EP_RX_ADDRESS(USB, ep->num, ep->pmaadress); 343 | PCD_SET_EP_RX_CNT(USB, ep->num, ep->maxpacket); 344 | PCD_CLEAR_RX_DTOG(USB, ep->num); 345 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_VALID); 346 | } 347 | } 348 | 349 | static void USB_EP_Deactivate(USB_EP_t *ep) 350 | { 351 | #ifdef USE_EP_DOUBLEBUFFER 352 | if (ep->doublebuffer) 353 | { 354 | PCD_CLEAR_RX_DTOG(USB, ep->num); 355 | PCD_CLEAR_TX_DTOG(USB, ep->num); 356 | if (ep->is_in) 357 | { 358 | PCD_RX_DTOG(USB, ep->num); 359 | } 360 | else 361 | { 362 | PCD_TX_DTOG(USB, ep->num); 363 | } 364 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_DIS); 365 | PCD_SET_EP_TX_STATUS(USB, ep->num, USB_EP_TX_DIS); 366 | return; 367 | } 368 | #endif //USE_EP_DOUBLEBUFFER 369 | if (ep->is_in) 370 | { 371 | PCD_CLEAR_TX_DTOG(USB, ep->num); 372 | PCD_SET_EP_TX_STATUS(USB, ep->num, USB_EP_TX_DIS); 373 | } 374 | else 375 | { 376 | PCD_CLEAR_RX_DTOG(USB, ep->num); 377 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_DIS); 378 | } 379 | } 380 | 381 | 382 | #ifdef USE_EP_DOUBLEBUFFER 383 | static uint16_t USB_EP_ReceiveDB(USB_EP_t *ep, uint16_t epReg) 384 | { 385 | bool db0 = epReg & USB_EP_DTOG_RX; 386 | uint16_t count; 387 | uint16_t pmaaddr; 388 | if (db0) 389 | { 390 | count = PCD_GET_EP_DBUF0_CNT(USB, ep->num); 391 | pmaaddr = ep->pmaaddr0; 392 | } 393 | else 394 | { 395 | count = PCD_GET_EP_DBUF1_CNT(USB, ep->num); 396 | pmaaddr = ep->pmaaddr1; 397 | } 398 | 399 | if (ep->type == EP_TYPE_BULK) 400 | { 401 | ep->xfer_len = ep->xfer_len >= count ? ep->xfer_len - count : 0; 402 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_NAK); 403 | 404 | bool db1 = epReg & USB_EP_DTOG_TX; 405 | if (db0 == db1) 406 | { 407 | // I dont quite understand this logic. 408 | // It seems the buffers are swapped in this case. 409 | PCD_TX_DTOG(USB, ep->num); 410 | } 411 | } 412 | else 413 | { 414 | PCD_TX_DTOG(USB, ep->num); 415 | } 416 | 417 | USB_PMA_Read(pmaaddr, ep->xfer_buff, count); 418 | return count; 419 | } 420 | 421 | static void USB_EP_TransmitDB(USB_EP_t *ep, uint16_t epReg) 422 | { 423 | bool db0 = epReg & USB_EP_DTOG_TX; 424 | uint16_t count; 425 | if (db0) 426 | { 427 | count = PCD_GET_EP_DBUF0_CNT(USB, ep->num); 428 | } 429 | else 430 | { 431 | count = PCD_GET_EP_DBUF1_CNT(USB, ep->num); 432 | } 433 | 434 | if (ep->xfer_len == 0) 435 | { 436 | HAL_PCD_DataInStageCallback(hpcd, ep->num); 437 | } 438 | 439 | bool db1 = epReg & USB_EP_DTOG_RX; 440 | if (db0 == db1) 441 | { 442 | PCD_RX_DTOG(USB, ep->num); 443 | } 444 | 445 | if (ep->xfer_len && ep->xfer_fill_db) 446 | { 447 | ep->xfer_buff += count; 448 | ep->xfer_count += count; 449 | 450 | uint32_t nextCount; 451 | if (ep->xfer_len_db >= ep->maxpacket) 452 | { 453 | nextCount = ep->maxpacket; 454 | ep->xfer_len_db -= nextCount; 455 | } 456 | else if (ep->xfer_len_db == 0) 457 | { 458 | nextCount = count; 459 | ep->xfer_fill_db = 0; 460 | } 461 | else 462 | { 463 | ep->xfer_fill_db = 0; 464 | nextCount = ep->xfer_len_db; 465 | ep->xfer_len_db = 0; 466 | } 467 | 468 | if (db0) 469 | { 470 | PCD_SET_EP_DBUF0_CNT(hpcd->Instance, ep->num, ep->is_in, nextCount); 471 | USB_PMA_Write(ep->pmaaddr0, ep->xfer_buff, nextCount); 472 | } 473 | else 474 | { 475 | PCD_SET_EP_DBUF1_CNT(hpcd->Instance, ep->num, ep->is_in, nextCount); 476 | USB_PMA_Write(ep->pmaaddr1, ep->xfer_buff, nextCount); 477 | } 478 | } 479 | PCD_SET_EP_TX_STATUS(hpcd->Instance, ep->num, USB_EP_TX_VALID); 480 | } 481 | #endif //USE_EP_DOUBLEBUFFER 482 | 483 | static void USB_EP_StartIn(USB_EP_t *ep) 484 | { 485 | uint32_t len; 486 | 487 | if (ep->xfer_len > ep->maxpacket) 488 | { 489 | len = ep->maxpacket; 490 | } 491 | else 492 | { 493 | len = ep->xfer_len; 494 | } 495 | 496 | #ifdef USE_EP_DOUBLEBUFFER 497 | if (ep->doublebuffer) 498 | { 499 | uint32_t pmabuffer; 500 | 501 | if (ep->type == EP_TYPE_BULK) 502 | { 503 | if (ep->xfer_len_db > ep->maxpacket) 504 | { 505 | PCD_SET_EP_DBUF(USB, ep->num); 506 | 507 | bool db1 = PCD_GET_ENDPOINT(USB, ep->num) & USB_EP_DTOG_TX; 508 | 509 | if (db1) 510 | { 511 | PCD_SET_EP_DBUF1_CNT(USB, ep->num, 1, len); 512 | pmabuffer = ep->pmaaddr1; 513 | } 514 | else 515 | { 516 | PCD_SET_EP_DBUF0_CNT(USB, ep->num, 1, len); 517 | pmabuffer = ep->pmaaddr0; 518 | } 519 | 520 | USB_PMA_Write(pmabuffer, ep->xfer_buff, len); 521 | ep->xfer_len_db -= len; 522 | ep->xfer_buff += len; 523 | if (ep->xfer_len_db > ep->maxpacket) 524 | { 525 | ep->xfer_len_db -= len; 526 | } 527 | else 528 | { 529 | len = ep->xfer_len_db; 530 | ep->xfer_len_db = 0; 531 | } 532 | 533 | if (db1) 534 | { 535 | PCD_SET_EP_DBUF0_CNT(USB, ep->num, 1, len); 536 | pmabuffer = ep->pmaaddr0; 537 | } 538 | else 539 | { 540 | PCD_SET_EP_DBUF1_CNT(USB, ep->num, 1, len); 541 | pmabuffer = ep->pmaaddr1; 542 | } 543 | 544 | USB_PMA_Write(pmabuffer, ep->xfer_buff, len); 545 | } 546 | else 547 | { 548 | // Double buffer not required for this payload 549 | len = ep->xfer_len_db; 550 | PCD_CLEAR_EP_DBUF(USB, ep->num); 551 | PCD_SET_EP_TX_CNT(USB, ep->num, len); 552 | pmabuffer = ep->pmaaddr0; 553 | USB_PMA_Write(pmabuffer, ep->xfer_buff, len); 554 | } 555 | } 556 | else // ISO Doublebuffer 557 | { 558 | if ((PCD_GET_ENDPOINT(USB, ep->num) & USB_EP_DTOG_TX) != 0U) 559 | { 560 | PCD_SET_EP_DBUF1_CNT(USB, ep->num, 1, len); 561 | pmabuffer = ep->pmaaddr1; 562 | } 563 | else 564 | { 565 | PCD_SET_EP_DBUF0_CNT(USB, ep->num, 1, len); 566 | pmabuffer = ep->pmaaddr0; 567 | } 568 | 569 | USB_PMA_Write(pmabuffer, ep->xfer_buff, (uint16_t)len); 570 | PCD_RX_DTOG(USB, ep->num); 571 | } 572 | } 573 | else 574 | #endif //USE_EP_DOUBLEBUFFER 575 | { 576 | USB_PMA_Write(ep->pmaadress, ep->xfer_buff, len); 577 | PCD_SET_EP_TX_CNT(USB, ep->num, len); 578 | } 579 | 580 | PCD_SET_EP_TX_STATUS(USB, ep->num, USB_EP_TX_VALID); 581 | } 582 | 583 | static void USB_EP_StartOut(USB_EP_t *ep) 584 | { 585 | uint32_t len; 586 | #ifdef USE_EP_DOUBLEBUFFER 587 | if (ep->doublebuffer) 588 | { 589 | if (ep->type == EP_TYPE_BULK) 590 | { 591 | PCD_SET_EP_DBUF_CNT(USB, ep->num, 0, ep->maxpacket); 592 | 593 | // Coming from ISR 594 | if (ep->xfer_count != 0U) 595 | { 596 | // Check if buffers are blocked. 597 | uint16_t epReg = PCD_GET_ENDPOINT(USB, ep->num); 598 | if ((((epReg & USB_EP_DTOG_RX) != 0U) && ((epReg & USB_EP_DTOG_TX) != 0U)) || 599 | (((epReg & USB_EP_DTOG_RX) == 0U) && ((epReg & USB_EP_DTOG_TX) == 0U))) 600 | { 601 | PCD_TX_DTOG(USB, ep->num); 602 | } 603 | } 604 | } 605 | else if (ep->type == EP_TYPE_ISOC) 606 | { 607 | // ISO out doublebuffer 608 | if (ep->xfer_len > ep->maxpacket) 609 | { 610 | len = ep->maxpacket; 611 | ep->xfer_len -= len; 612 | } 613 | else 614 | { 615 | len = ep->xfer_len; 616 | ep->xfer_len = 0; 617 | } 618 | PCD_SET_EP_DBUF_CNT(USB, ep->num, 0, len); 619 | } 620 | } 621 | else 622 | #endif //USE_EP_DOUBLEBUFFER 623 | { 624 | if (ep->xfer_len > ep->maxpacket) 625 | { 626 | len = ep->maxpacket; 627 | ep->xfer_len -= len; 628 | } 629 | else 630 | { 631 | len = ep->xfer_len; 632 | ep->xfer_len = 0U; 633 | } 634 | PCD_SET_EP_RX_CNT(USB, ep->num, len); 635 | } 636 | 637 | PCD_SET_EP_RX_STATUS(USB, ep->num, USB_EP_RX_VALID); 638 | } 639 | 640 | /* 641 | * INTERRUPT ROUTINES 642 | */ 643 | 644 | 645 | void USB_EP_IRQHandler(void) 646 | { 647 | while (USB->ISTR & USB_ISTR_CTR) 648 | { 649 | uint32_t istr = USB->ISTR; 650 | uint8_t epnum = (uint8_t)(istr & USB_ISTR_EP_ID); 651 | uint16_t epReg = PCD_GET_ENDPOINT(USB, epnum); 652 | 653 | // Control endpoint 654 | if (epReg & USB_EP_CTR_TX) 655 | { 656 | // IN endpoint 657 | USB_EP_t * ep = &gEP.in_ep[epnum]; 658 | PCD_CLEAR_TX_EP_CTR(USB, epnum); 659 | 660 | #ifdef USE_EP_DOUBLEBUFFER 661 | if (epReg & USB_EP_KIND && ep->type == USB_EP_TYPE_BULK) 662 | { 663 | USB_EP_TransmitDB(ep, epReg); 664 | } 665 | else 666 | #endif 667 | { 668 | uint16_t count = (uint16_t)PCD_GET_EP_TX_CNT(USB, ep->num); 669 | ep->xfer_len = ep->xfer_len > count ? ep->xfer_len - count : 0; 670 | if (ep->xfer_len == 0) 671 | { 672 | // Transfer is complete 673 | ep->callback(ep->xfer_count); 674 | } 675 | else 676 | { 677 | // Transfer is not yet done 678 | ep->xfer_buff += count; 679 | ep->xfer_count += count; 680 | USB_EP_StartIn(ep); 681 | } 682 | } 683 | } 684 | else 685 | { 686 | // OUT endpoint 687 | USB_EP_t * ep = &gEP.out_ep[epnum]; 688 | if (epReg & USB_EP_SETUP) 689 | { 690 | ep->xfer_count = PCD_GET_EP_RX_CNT(USB, ep->num); 691 | 692 | // Handle this transfer in a local buffer. The xfer_buff will not be allocated. 693 | uint8_t setup[8]; 694 | USB_PMA_Read(ep->pmaadress, setup, ep->xfer_count); 695 | 696 | // SETUP bit kept frozen while CTR_RX 697 | PCD_CLEAR_RX_EP_CTR(USB, 0); 698 | USB_CTL_HandleSetup(setup); 699 | } 700 | else if (epReg & USB_EP_CTR_RX) 701 | { 702 | PCD_CLEAR_RX_EP_CTR(USB, epnum); 703 | 704 | uint16_t count; 705 | #ifdef USE_EP_DOUBLEBUFFER 706 | if (ep->doublebuffer) 707 | { 708 | count = USB_EP_ReceiveDB(ep, epReg); 709 | } 710 | else 711 | #endif //USE_EP_DOUBLEBUFFER 712 | { 713 | count = PCD_GET_EP_RX_CNT(USB, ep->num); 714 | if (count) 715 | { 716 | USB_PMA_Read(ep->pmaadress, ep->xfer_buff, count); 717 | } 718 | } 719 | 720 | ep->xfer_count += count; 721 | ep->xfer_buff += count; 722 | 723 | if (count < ep->maxpacket || ep->xfer_len == 0) 724 | { 725 | ep->callback(ep->xfer_count); 726 | } 727 | else 728 | { 729 | USB_EP_StartOut(ep); 730 | } 731 | } 732 | } 733 | } 734 | } 735 | 736 | #endif //USB_ENABLE 737 | -------------------------------------------------------------------------------- /preprocessor.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os.path 3 | import io 4 | 5 | IF_STATE_NOW = 0 6 | IF_STATE_SEEK = 1 7 | IF_STATE_SKIP = 2 8 | 9 | TOKEN_SEARCH_REGEX = re.compile(r"(\w+)") 10 | PAREN_SEARCH_REGEX = re.compile(r"\s*\(") 11 | VA_ARG_REGEX = re.compile(r"(\w*)(?:(? [] 300 | def _directive_define(self, args): 301 | self.define(args[0], args[1]) 302 | 303 | # Rule to handle: #define () [] 304 | def _directive_define_varidic(self, args): 305 | varargs = [ a.strip() for a in args[1].split(",") ] 306 | self.define(args[0], args[2], varargs) 307 | 308 | # Rule to handle: #if 309 | def _directive_if(self, args): 310 | self._flow_enter_if(self._test_expression(args[0])) 311 | 312 | # Rule to handle: #ifdef 313 | def _directive_ifdef(self, args): 314 | self._flow_enter_if(self.is_defined(args[0])) 315 | 316 | # Rule to handle: #ifndef 317 | def _directive_ifndef(self, args): 318 | self._flow_enter_if(not self.is_defined(args[0])) 319 | 320 | # Rule to handle: #else 321 | def _directive_else(self, args): 322 | self._flow_else_if(True) 323 | 324 | # Rule to handle: #elif 325 | def _directive_elif(self, args): 326 | self._flow_else_if(self._test_expression(args[0])) 327 | 328 | # Rule to handle: #endif 329 | def _directive_endif(self, args): 330 | self._flow_exit_if() 331 | 332 | # Rule to handle: #include 333 | def _directive_include(self, args): 334 | token = self.expand(args[0]) 335 | if len(token) < 2 or (token[0] + token[-1]) not in ['""', '<>']: 336 | raise Exception("Invalid include argument") 337 | fname = token[1:-1] 338 | if self.include_rule(fname): 339 | self.include(fname, may_ignore=self.ignore_missing_includes) 340 | 341 | # Rule to handle: #error 342 | def _directive_error(self, args): 343 | raise Exception("#error {0}".format(args[0])) 344 | 345 | # Rule to handle: #undef 346 | def _directive_undef(self, args): 347 | self.undefine(args[0]) 348 | 349 | # Rule to handle: #pragma 350 | def _directive_pragma(self, args): 351 | 352 | # custom pragma to execute python within the source. Useful for debugging. 353 | # #pragma python "print(p.macros)" 354 | # The current preprocessor instance is passed as the only local: p 355 | match = re.match(r"python\s+\"([^\"]*)\"", args[0]) 356 | if match: 357 | expr = match.groups()[0] 358 | eval(expr, None, { "p": self }) 359 | 360 | 361 | # 362 | # MACRO EXPANSION 363 | # 364 | 365 | # Scans for the end of a string 366 | def _find_string_end(self, line, pos, endchar): 367 | while pos < len(line): 368 | if line[pos] == endchar: 369 | return pos + 1 370 | elif line[pos] == "\\": 371 | pos += 2 372 | else: 373 | pos += 1 374 | raise Exception("Unterminated string") 375 | 376 | # Looks for a closed pair of parentheses in the line. 377 | # If found, returns the index of the first character after the pair. 378 | # If not found, returns -1. 379 | def _find_parentheses_end(self, line, start): 380 | # find the matching parenthesis 381 | depth = 1 382 | i = start 383 | while i < len(line): 384 | if line[i] == '(': 385 | depth += 1 386 | elif line[i] == ')': 387 | depth -= 1 388 | if depth == 0: 389 | return i + 1 390 | elif line[i] in "'\"": 391 | i = self._find_string_end(line, i+1, line[i]) 392 | continue 393 | i += 1 394 | return None 395 | 396 | # Finds the arguments (), taking care to skip embedded strings 397 | def _find_arguments(self, line, start): 398 | match = PAREN_SEARCH_REGEX.match(line, start) 399 | if match: 400 | start = match.end() 401 | end = self._find_parentheses_end(line, start) 402 | return start-1, end 403 | return None, None 404 | 405 | # Finds the next valid token to consider for macro replacement 406 | def _find_token(self, line, start): 407 | while True: 408 | # find a candidate token 409 | match = TOKEN_SEARCH_REGEX.search(line, start) 410 | if not match: 411 | break 412 | i = start 413 | start = match.start() 414 | while i < start: 415 | # if we hit a string, skip over it 416 | if line[i] in "'\"": 417 | i = self._find_string_end(line, i+1, line[i]) 418 | else: 419 | i += 1 420 | 421 | if i > start: 422 | # Did we skip our token? 423 | # If so, it must have been in a stirng. 424 | start = i 425 | else: 426 | return match.span() 427 | return None, None 428 | 429 | # splits an argument string into a list of arguments 430 | # care should be taken not to split inside a string or parenthesis 431 | # NOTE: whitespace strip is now handled in Macro._substitute_args() 432 | def _split_args(self, args): 433 | arglist = [] 434 | i = 0 435 | arg_start = 0 436 | while i < len(args): 437 | if args[i] in "'\"": 438 | i = self._find_string_end(args, i+1, args[i]) 439 | elif args[i] == '(': 440 | i = self._find_parentheses_end(args, i+1) 441 | elif args[i] == ',': 442 | arglist.append(args[arg_start:i]) 443 | arg_start = i + 1 444 | i += 1 445 | else: 446 | i += 1 447 | arglist.append(args[arg_start:]) 448 | return arglist 449 | 450 | 451 | # Expands all macros in the given expression 452 | def expand(self, expr): 453 | expr, remainder = self._expand_macros(expr) 454 | if remainder: 455 | raise Exception("Unterminated macro in expression") 456 | return expr 457 | 458 | def _is_empty_token(self, token): 459 | # If _split_args could return stripped arguments (ie, it was aware of whether it was parsing varargs or not) 460 | # Then this could be replaced with simply (not token) 461 | return (not token) or token.isspace() 462 | 463 | # Expands all macros in the given expression 464 | # May return a remainder string if the expression is not fully expanded 465 | def _expand_macros(self, expr): 466 | expansion_depth = 0 467 | # expand macros 468 | start = 0 469 | while True: 470 | 471 | # find a token for consideration 472 | start, end = self._find_token(expr, start) 473 | if start == None: 474 | break 475 | token = expr[start:end] 476 | 477 | macro_expr = None 478 | if token in self.macros: 479 | 480 | # check we arent caught in a loop 481 | if expansion_depth > self.max_macro_expansion_depth: 482 | raise Exception(f"Max macro expansion depth exceeded (in expression \"{expr.strip()}\")") 483 | 484 | # expand the macro 485 | macro = self.macros[token] 486 | if macro.args != None: 487 | 488 | # find the arguments 489 | arg_start, arg_end = self._find_arguments(expr, end) 490 | if arg_start != None: 491 | if arg_end == None: 492 | # We have an unterminated argument list. 493 | # this line will have to be glued to the next line. 494 | return None, expr 495 | 496 | # separate the arguments 497 | args = self._split_args(expr[arg_start+1:arg_end-1]) 498 | 499 | # Handle the case where macro is called with an empty argument list 500 | if len(args) == 1 and len(macro.args) == 0 and self._is_empty_token(args[0]): 501 | args = [] 502 | 503 | if len(args) != len(macro.args) and not any([re.search(VA_ARG_REGEX, macro.args[i]) for i in range(len(macro.args))]): 504 | raise Exception("Macro \"{0}\" requires {1} arguments (in expression \"{2}\")".format(token, len(macro.args), expr.strip())) 505 | 506 | # replace the macro with the expanded expression 507 | macro_expr = macro.expand(args) 508 | end = arg_end 509 | else: 510 | # expand the macro without arguments 511 | macro_expr = macro.expand() 512 | 513 | if macro_expr != None: 514 | # we have our new string 515 | expr = expr[:start] + macro_expr + expr[end:] 516 | # do not increase the start point - we should recheck this for new tokens to be expanded. 517 | expansion_depth += 1 518 | else: 519 | # proceed over the token 520 | start = end 521 | 522 | return expr, None 523 | 524 | # 525 | # EXPRESSION EVALUATION 526 | # 527 | 528 | # Evaluates an expression 529 | def evaluate(self, expr): 530 | 531 | self.macros["defined"] = self._defined_macro 532 | expr = self.expand(expr) 533 | del self.macros["defined"] 534 | 535 | # convert to python expression (this may be very dangerous) 536 | expr = expr.replace("&&", " and ") 537 | expr = expr.replace("||", " or ") 538 | expr = expr.replace("/", "//") 539 | expr = re.sub(r"!([^?==])", r" not \1", expr) 540 | 541 | result = eval(expr) 542 | return result 543 | 544 | # Tests an expression for truth. 545 | def _test_expression(self, expr): 546 | try: 547 | result = self.evaluate(expr) 548 | if type(result) is str: 549 | return False 550 | return bool(result) 551 | except: 552 | return False 553 | 554 | # 555 | # FLOW EVALUATION 556 | # 557 | 558 | # Enters a new #if block 559 | def _flow_enter_if(self, enabled): 560 | self._enable_stack.append(self._content_enabled) 561 | if self._content_enabled == IF_STATE_NOW: 562 | self._content_enabled = IF_STATE_NOW if enabled else IF_STATE_SEEK 563 | else: 564 | # Our current if block is disabled. Stop us from matching any until we exit. 565 | self._content_enabled = IF_STATE_SKIP 566 | 567 | # Exist the last #if block 568 | def _flow_exit_if(self): 569 | if not len(self._enable_stack): 570 | raise Exception("Unexpected #endif reached") 571 | self._content_enabled = self._enable_stack.pop(-1) 572 | 573 | # Passes through an #else block 574 | def _flow_else_if(self, enabled): 575 | 576 | if self._content_enabled == IF_STATE_NOW: 577 | # we may no longer match other if blocks. 578 | self._content_enabled = IF_STATE_SKIP 579 | elif self._content_enabled == IF_STATE_SEEK and enabled: 580 | # Only accept the new state if we have not yet matched an if block. 581 | self._content_enabled = IF_STATE_NOW 582 | 583 | # returns true if the current #if block is enabled 584 | def _flow_enabled(self): 585 | return self._content_enabled == IF_STATE_NOW 586 | --------------------------------------------------------------------------------