#include "usbapp/usb_application_flash.h" #include "usb/usb_bridge.h" #include "usb/usb_config.h" #include "usbd_vendor.h" #include "drivers/flash/base/extmem_flash.h" #include "core/csect.h" #include "core/config.h" #include "app/nfm/nfm_base.h" #define PROTO_REQ_READ_DATA_FLASH 0x02 // прочитать данные из флеш (режим эмуляции банков) #define PROTO_REQ_WRITE_DATA_FLASH 0x03 // записать данные во флеш (режим эмуляции банков) #define PROTO_REQ_GET_FLAG_FLASH_STATUS 0x06 // считать состояние статуса записи флеша #define PROTO_REQ_SET_PROTECT_FLASH 0x07 // установить защиту флеша #define PROTO_REQ_READ_DATA_FLASH_EX 0xA3 // прочитать данные из флеши (линейный экспертный режим) #define PROTO_REQ_READ_INFO 0xA4 // чтение служебной информации #define PROTO_REQ_WRITE_DATA_FLASH_LIN 0xA5 // записать данные во флеш (линейный режим) #define PROTO_REQ_READ_DATA_FLASH_LIN 0xA6 // прочитать данные из флеш (линейный режим) static int8_t fFlashAppInit(); static int8_t fFlashAppDeInit(); static void fFlashAppReset(); static bool fFlashAppSetup( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success ); static size_t fFlashAppControlRx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ); static size_t fFlashAppControlTx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining ); const sUSBAppEntry_Control_t usbapplication_ACM_planarproto_flash = { .fUsbInit = fFlashAppInit, .fUsbDeInit = fFlashAppDeInit, .fUsbSetup = fFlashAppSetup, .fUsbCtlEpRx = fFlashAppControlRx, .fUsbCtlEpTx = fFlashAppControlTx, .fResetEvent = fFlashAppReset, }; //----------------------------------------------------- static sUSBTransfer_t transf_write_flash; static flash_address_t WritingAddress = 0; static volatile bool bFlagWritingInProgress = false; static inline bool fGetWritingFlag() { bool flag; __DI__ flag = bFlagWritingInProgress; __EI__ return flag; } bool usb_application_flash_fGetWritingFlag() { return fGetWritingFlag(); } /* static inline void fSetWritingFlag() { __DI__ bFlagWritingInProgress = true; __EI__ } */ static inline void fClrWritingFlag() { __DI__ bFlagWritingInProgress = false; __EI__ } static inline bool fTrySetWritingFlag() { bool flag = false; __DI__ if( ! bFlagWritingInProgress ) { bFlagWritingInProgress = flag = true; } __EI__ return flag; } //----------------------------------------------------- static size_t fFlashApp_ReadDataFlash( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining ); static size_t fFlashApp_WriteDataFlash( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ); static size_t fFlashApp_ReadReadyFlash( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ); static bool fFlashApp_SetProtectionFlash( const tUSBSetupPacket_t * pSetup ); // &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& &&&& static int8_t fFlashAppInit() { return 0; } // &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- static int8_t fFlashAppDeInit() { return 0; } // &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- static void fFlashAppReset() { } // &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- static bool fFlashAppSetup( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success ) { switch ( pSetup->bRequest ) { case PROTO_REQ_READ_DATA_FLASH: { // check device ready if( fGetWritingFlag() ) { return false; // device busy } else { return (bool)fFlashApp_ReadDataFlash( pSetup, NULL, 0, 0 ); } } break; case PROTO_REQ_WRITE_DATA_FLASH: { // check device ready if( fGetWritingFlag() ) { return false; // device busy } else { return (bool)fFlashApp_WriteDataFlash( pSetup, NULL, 0, 0 );; } } break; case PROTO_REQ_GET_FLAG_FLASH_STATUS: { return true; // accept } break; case PROTO_REQ_SET_PROTECT_FLASH: { // perform factory-memory bank protection: inside this IRQ routine switch( pSetup->wValue ) { case 0x0000: case 0x0001: { // 0x0000, 0x0001 return fFlashApp_SetProtectionFlash( pSetup ); } } } break; } return false; } // &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- static size_t fFlashAppControlRx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining ) { switch ( pSetup->bRequest ) { case PROTO_REQ_WRITE_DATA_FLASH: { return fFlashApp_WriteDataFlash( pSetup, rx, idx, bytesRemaining ); } break; } return 0; } // &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- &&&& ---- static size_t fFlashAppControlTx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ) { switch ( pSetup->bRequest ) { case PROTO_REQ_READ_DATA_FLASH: { return fFlashApp_ReadDataFlash( pSetup, tx, idx, bytesRemaining ); } break; case PROTO_REQ_GET_FLAG_FLASH_STATUS: { return fFlashApp_ReadReadyFlash( pSetup, tx, idx, bytesRemaining ); } break; } return 0; } // &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- static size_t fFlashApp_ReadDataFlash( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ) { flash_address_t chunk_address = idx + (flash_address_t)pSetup->wIndex + (((flash_address_t)pSetup->wValue)<<16); if( NULL == tx ) { return ((ExtMemHandle.RangeCheck_Read( chunk_address, bytesRemaining ))?1:0); } flash_size_t chunk_bytes = MIN( bytesRemaining, usb_space_transfer( tx ) ); if( ExtMemHandle.Read( chunk_address, usb_transfer_raw_write(tx), chunk_bytes ) ) { return usb_transfer_virtual_write( tx, chunk_bytes ); } return 0; } // &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- static size_t fFlashApp_WriteDataFlash( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining ) { flash_address_t chunk_address = idx + (flash_address_t)pSetup->wIndex + (((flash_address_t)pSetup->wValue)<<16); if( NULL == rx ) { // For normal operation it is required that whole the packet // fits to the Low-Level RX-buffer (aka RX-transfer), and this // event fires only when all the data already received. // This fact guaranees that the application CAN USE MOVE SEMANTIC // on the RX-transfer because it is a last RX-event in the sequence. if( pSetup->wLength > USBD_VENDOR_get_control_rx_transfer_size() ) { // No, the whole transfer length is greater than RX-transfer size. // Partial writing is not supported // Whole packet must fit into the transfer size. return false; } return ((ExtMemHandle.RangeCheck_Write( chunk_address, bytesRemaining ))?1:0); } // Check device ready and set busy flag if( fTrySetWritingFlag() ) { flash_size_t chunk_bytes = MIN( bytesRemaining, usb_count_transfer( rx ) ); // For normal operation it is required that whole the packet // fits to the Low-Level RX-buffer (aka RX-transfer), and this // event fires only when all the data already received. // This fact guaranees that the application CAN USE MOVE SEMANTIC // on the RX-transfer because it is a last RX-event in the sequence. // Check if all the data already is in the transfer: if( (0 == idx) && (usb_count_transfer( rx ) == bytesRemaining) ) { // Ok, all conditions are true // use MOVE SEMANTIC on the passed transfer @rx // Make the source @rx transfer invalid // Move all resources from @rx to the new object @transf_write_flash // After the operation the source @rx transfer will be invalid. // The core will not be able use internal RX-transfer (specified by @rx). // Need to move the transfer back usb_move_transfer( &transf_write_flash, rx, false ); // Remember region parameters WritingAddress = chunk_address; // It is required to remember the transfer object the move semantic implemented on. // Use user context value of the transfer objects: store the @rx pointer into the @transf_write_flash usb_transfer_set_context( &transf_write_flash, rx ); // NOW USB-CORE UNABLE TO RECEIVE DATA!!! // Internal USB-CORE RX-buffer is moved to the @transf_write_flash object! // report the core that all return usb_count_transfer( &transf_write_flash ); } // on error case: reset the flag fClrWritingFlag(); } return 0; } // &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- static size_t fFlashApp_ReadReadyFlash( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ) { flash_size_t chunk_bytes = MIN( bytesRemaining, usb_space_transfer( tx ) ); uint8_t value[2] = { 0x00 }; if( fGetWritingFlag() ) value[0] = 0x00A5; else value[0] = 0x0000; if( (idx < sizeof( value )) && (bytesRemaining <= sizeof( value )) ) { usb_push_transfer( tx, &value[idx], bytesRemaining ); } return usb_count_transfer( tx ); } // &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- static bool fFlashApp_SetProtectionFlash( const tUSBSetupPacket_t * pSetup ) { bool ret = false; switch( pSetup->wValue ) { case 0x0000: { #if CONFIG_NFMBASECLASS ret = NFMClass->methods.xMemoryProtection.enable(); #else ret = ExtMemHandle.BankProtect( extmem_bank_factory, true ) // Set BANK0 protection && ExtMemHandle.BankProtect( extmem_bank_user, false ); // Clear BANK1 protection (always unprotected) #endif } break; case 0x0001: { #if CONFIG_NFMBASECLASS ret = NFMClass->methods.xMemoryProtection.disable(); #else ret = ExtMemHandle.BankProtect( extmem_bank_factory, false ) // Clear BANK0 protection && ExtMemHandle.BankProtect( extmem_bank_user, false ); // Clear BANK1 protection (always unprotected) #endif } break; } /* 30/05/19, Testing asm("bkpt #0"); bool bank0 = false; bool bank1 = false; ExtMemHandle.CheckBankProtect( extmem_bank_factory, &bank0 ); ExtMemHandle.CheckBankProtect( extmem_bank_user, &bank1 ); asm("bkpt #0"); ExtMemHandle.BankProtect( extmem_bank_factory, false ); ExtMemHandle.BankProtect( extmem_bank_user, false ); asm("bkpt #0"); ExtMemHandle.BankProtect( extmem_bank_factory, true ); ExtMemHandle.BankProtect( extmem_bank_user, false ); asm("bkpt #0"); ExtMemHandle.BankProtect( extmem_bank_factory, false ); ExtMemHandle.BankProtect( extmem_bank_user, true ); asm("bkpt #0"); ExtMemHandle.BankProtect( extmem_bank_factory, true ); ExtMemHandle.BankProtect( extmem_bank_user, true ); asm("bkpt #0"); (void)bank0; (void)bank1; */ return ret; } // &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- &--& ---- void usb_application_flash_serve() { // Serve the flash u-application // Check if the writing flag is set if( fGetWritingFlag() ) { #if CONFIG_NFMCLASS_AUTOPROTECT_MEMORY // protect factory data: set memory protection NFMClass->methods.xMemoryProtection.disable(); #endif // retireve the data pointer void * pWriteData = usb_transfer_raw_read( &transf_write_flash ); flash_address_t WritingSize = usb_count_transfer( &transf_write_flash ); // perform the writing ExtMemHandle.Write( WritingAddress, pWriteData, WritingSize ); // It is required to return the USB-CORE buffer back. sUSBTransfer_t * usb_core_rx_transfer = NULL; // Retrieve the core-transfer object pointer from the @transf_write_flash context value: if( usb_transfer_get_context( &transf_write_flash, (void**)&usb_core_rx_transfer ) ) { // Move the memory buffer back to the CORE: usb_move_transfer( usb_core_rx_transfer, &transf_write_flash, false ); // Reset transfer (optional) usb_reset_transfer( usb_core_rx_transfer ); } // Reset the writing flag fClrWritingFlag(); #if CONFIG_NFMCLASS_AUTOPROTECT_MEMORY // protect factory data: set memory protection NFMClass->methods.xMemoryProtection.enable(); #endif } }