#define __CORE_USB_HEADER__ #include "usb/usb_bridge.h" #include "usb/usb_config.h" #include "usbd_vendor.h" // PLANAR Protocol #include "usbd_usbtmc.h" // USBTMC Protocol #include "core/config.h" // CONFIG_AUTOMAT_MODE_USB_POWERBANK #include "core/gpio.h" #include "usbapp/usb_application_switch.h" #include "usbapp/usb_application_flash.h" #include "usbapp/usb_application_temp.h" #if CONFIG_AUTOMAT_MODE_USB_POWERBANK && CONFIG_AUTOMAT_MODE #include "usbapp/usb_application_enumspy.h" #endif #include "usbapp/usb_application_usbtmc.h" #include "usbapp/usb_application_benchmark.h" #include "usbapp/usb_application_service.h" #include "usbapp/usb_application_default_dataapp.h" #include "usbapp/usb_application_interfaceswitch.h" #include "usbapp/usb_application_power.h" #include "usbapp/usb_application_led.h" // Module usb_bridge // File: usb_bridge.c // Description: this module connects the middleware USBD-drivers and user USB // applications using so calling "bridges". // The bridge - is a user declared special structure that announces the application // in the module application pool - this process is also knowed as "registering". // The registering process is fully static process. Once registerd the application // can not be unregisted. In the same time there no way to register application in runtime. // Each USBD-class (VENDOR, USBTMC, etc.) have dedicated application pool. // For example: VENDOR interface is responsible for PLANAR protocol that used to // interact to the host applications using VENDOR-requests only via CONTROL transfers. // This VENDOR interface has application pool: @usbCtlAppList_Vendor. // Each set of logically combined vendor-specific requests represent "application". // You must register such sets in the @usbCtlAppList_Vendor. // All the applications are services in order of registering in the pool. // The first application that successfully processed the CONTROL-request is considered // as an application that the request is intended for. // So you must delegate only unique requests for each application. // As for BULK transfers, the bridges for bulk transfers work some kind differ. // Unlike CONTROL transfer, the bulk ones does not relies on SETUP packets that // could help to identify the application the data is intended for. // Instead of the SETUP-requests, the data flow is being controlled by the USB endpoint // address (EP number). Unlike the CONTROL application, each data-application must register // the data handler dynamically during the CONTROL application initializing. // So, the data applications are depends on the control applications and can not be used // separately. The pool for the data applications have equal size as a number of hardware // possible number of data-endpoints plus one (including the only control endpoint). // This extra entry (for control endpoint) is reserved in the beginning of the pool and is // used for the endpoints are not occupated by any data-application, aka default handler. // Once registed the application can be unregisted in the any time. The endpoint // the application registered for remains occupied until the application is un-registered. // So only one data-application can be registered to serve each logical endpoint. // ----------------------------------------------------------------------------- #define cellsof(A) (sizeof(A)/sizeof(A[0])) #define lastcell(A) A[cellsof(A)] #define foreachidx_ctl_app_vendor(app,i) for( size_t i = ( app = usbCtlAppList_Vendor[0], 0 ); i < cellsof(usbCtlAppList_Vendor); app = usbCtlAppList_Vendor[++i] ) #define foreach_ctl_app_vendor(app) foreachidx_ctl_app_vendor(app,__i) #define foreachidx_ctl_app_usbtmc(app,i) for( size_t i = ( app = usbCtlAppList_Usbtmc[0], 0 ); i < cellsof(usbCtlAppList_Usbtmc); app = usbCtlAppList_Usbtmc[++i] ) #define foreach_ctl_app_usbtmc(app) foreachidx_ctl_app_usbtmc(app,__i) #define foreachidx_data_app_usbtmc(app,i) for( size_t i = ( app = usbDataAppList_Usbtmc[0], 0 ); i < cellsof(usbDataAppList_Usbtmc); app = usbDataAppList_Usbtmc[++i] ) #define foreach_data_app_usbtmc(app) foreachidx_ctl_app_usbtmc(app,__i) #define with_data_app_for(ep, app) if(((ep) > 0)\ && ((0x7F & (ep)) < (MAX_DATAAPP_ENDPOINTS))\ && (NULL != (app = usbDataAppList_Usbtmc[ (0x7F & (ep)) ], app) ) ) #define with_default_data_app(ep, app) if(((ep) > 0)\ && (NULL != (app = usbDataAppList_Usbtmc[ 0 ], app) ) ) // ----------------------------------------------------------------------------- // PLANAR protocol: application index // @usbCtlApp_appIdx_Vendor // stores the active application index the next control transaction // will be passed for. static size_t usbCtlApp_appIdx_Vendor = 0; // USBTMC protocol: application index // @usbCtlApp_appIdx_Usbtmc // stores the active application index the next control transaction // will be passed for. static size_t usbCtlApp_appIdx_Usbtmc = 0; /* --- Vendor Specific Applications --- PLANAR Protocol: 1. Application Key Switch [usb_application_switch.h] 2. Application Flash Control [usb_application_switch.h] 3. Application Temperature Monitor [usb_application_temp.h] 4. Application USB-Enumeration Spy [usb_application_enumspy.h] ------------------------------------- */ // PLANAR protocol: applications list // @usbCtlAppList_Vendor // USB Control Interface applications list static const sUSBAppEntry_Control_t * const usbCtlAppList_Vendor[] = { #if CONFIG_AUTOMAT_MODE_USB_POWERBANK && CONFIG_AUTOMAT_MODE &usbapplication_ACM_planarproto_enumspy, #endif &usbapplication_ACM_planarproto_flash, //&usbapplication_ACM_planarproto_temp, //&usbapplication_ACM_planarproto_switch, &usbapplication_ACM_planarproto_service, &usbapplication_ACM_planarproto_interfaceswitch, //&usbapplication_ACM_planarproto_power, &usbapplication_ACM_planarproto_led }; // USBTMC protocol: CONTROL-applications list // @usbCtlAppList_Usbtmc // USB Control Interface applications list static const sUSBAppEntry_Control_t * const usbCtlAppList_Usbtmc[] = { #if CONFIG_AUTOMAT_MODE_USB_POWERBANK && CONFIG_AUTOMAT_MODE &usbapplication_ACM_planarproto_enumspy, #endif &usbapplication_USBTMC_control, //&usbapplication_BENCHMARK_control, }; // USBTMC protocol: BULK-applications list // @usbDataAppList_Usbtmc // USB Bulk Interface applications list static const sUSBAppEntry_Data_t * usbDataAppList_Usbtmc[ MAX_DATAAPP_ENDPOINTS ] = { NULL // no applications registered by default: you must register applications in runtime }; // ----------------------------------------------------------------------------- // @usb_bridge_register_dataapp // Register (attach) the data-stream handler @dataApp for the specified endpoint (@epnum) // After the registering all the data requests relates to the endpoint will be routed to // the aproptiate handler. bool usb_bridge_register_dataapp( uint8_t epnum, const sUSBAppEntry_Data_t * dataApp ) { epnum = epnum & 0x7F; if( ((epnum > 0) && (epnum < MAX_DATAAPP_ENDPOINTS)) && ( NULL != dataApp ) ) { if( NULL == usbDataAppList_Usbtmc[ epnum ] ) { if( NULL == dataApp->fDataInitHandler ) { usbDataAppList_Usbtmc[ epnum ] = dataApp; return true; } else if( dataApp->fDataInitHandler( epnum ) ) { usbDataAppList_Usbtmc[ epnum ] = dataApp; return true; } } } return false; } // @usb_bridge_unregister_dataapp // De-Register (detach) the data-stream handler @dataApp from the specified endpoint (@epnum) // After the deregistering all the data requests relates to the endpoint will be routed to // the default data handler handler or will be discared bool usb_bridge_unregister_dataapp( uint8_t epnum ) { epnum = epnum & 0x7F; if( (epnum > 0) && (epnum < MAX_DATAAPP_ENDPOINTS) ) { if( (NULL != usbDataAppList_Usbtmc[ epnum ]) && (NULL != usbDataAppList_Usbtmc[ epnum ]->fDataDeInitHandler) ) { usbDataAppList_Usbtmc[ epnum ]->fDataDeInitHandler( epnum ); } usbDataAppList_Usbtmc[ epnum ] = NULL; return true; } return false; } // ----------------------------------------------------------------------------- // PLANAR protocol procedures: // "usblib"-layer procedures static int8_t fUsbInit_Vendor(); static void fUsbReset_Vendor(); static size_t fUsbEp0Rx_Vendor( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining ); static size_t fUsbEp0Tx_Vendor( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ); static bool fUsbSetInterface_Vendor( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc ); static void fUsbClrInterface_Vendor( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc ); static bool fUsbSetupRx_Vendor( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success ); static int8_t fUsbDeInit_Vendor(); // ----------------------------------------------------------------------------- // PLANAR Protocol: VENDOR bridge descriptor const USBD_COMMON_ItfTypeDef USBD_Interface_Vendor_UsbInterface = { .fUsbInit = fUsbInit_Vendor, // .fUsbDeInit = fUsbDeInit_Vendor, // .fUsbSetup = fUsbSetupRx_Vendor, // SETUP-packet filtering .fUsbCtlEpRx = fUsbEp0Rx_Vendor, // Control-transfer-OUT handler .fUsbCtlEpTx = fUsbEp0Tx_Vendor, // Control-transfer-IN handler .fResetEvent = fUsbReset_Vendor, // USB Reset handler .fSuspendEvent = NULL, // .fSetIface = fUsbSetInterface_Vendor, // SetInterface/SetConfiguration request handler .fClrIface = fUsbClrInterface_Vendor, // SetInterface/SetConfiguration request handler .fGetIface = NULL, // .fDataRxHandler = NULL, // Bulk-transfer-OUT handler .fDataTxHandler = NULL, // Bulk-transfer-IN handler .fDataErrHandler = NULL, // Bulk-transfer error handler }; // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // USBTMC protocol procedures: // "usblib"-layer procedures static int8_t fUsbInit_Usbtmc(); static void fUsbReset_Usbtmc(); static size_t fUsbEp0Rx_Usbtmc( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining ); static size_t fUsbEp0Tx_Usbtmc( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ); static bool fUsbSetInterface_Usbtmc( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc ); static void fUsbClrInterface_Usbtmc( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc ); static bool fUsbDataRx_Usbtmc( uint8_t bEpLogAddress, sUSBTransfer_t * rx ); static bool fUsbDataTx_Usbtmc( uint8_t bEpLogAddress, sUSBTransfer_t * tx ); static bool fUsbDataErr_Usbtmc( uint8_t bEpLogAddress, uint32_t err ); static bool fUsbSetupRx_Usbtmc( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success ); static int8_t fUsbDeInit_Usbtmc(); // USBTMC Protocol: USBTMC bridge descriptor #if CONFIG_USB_USBTMC_ENABLE const USBD_COMMON_ItfTypeDef USBD_Interface_Usbtmc_UsbInterface = { .fUsbInit = fUsbInit_Usbtmc, // .fUsbDeInit = fUsbDeInit_Usbtmc, // .fUsbSetup = fUsbSetupRx_Usbtmc, // SETUP-packet filtering .fUsbCtlEpRx = fUsbEp0Rx_Usbtmc, // Control-transfer-OUT handler .fUsbCtlEpTx = fUsbEp0Tx_Usbtmc, // Control-transfer-IN handler .fResetEvent = fUsbReset_Usbtmc, // USB Reset handler .fSuspendEvent = NULL, // .fSetIface = fUsbSetInterface_Usbtmc, // SetInterface/SetConfiguration request handler .fClrIface = fUsbClrInterface_Usbtmc, // SetInterface/SetConfiguration request handler .fGetIface = NULL, // .fDataRxHandler = fUsbDataRx_Usbtmc, // Bulk-transfer-OUT handler .fDataTxHandler = fUsbDataTx_Usbtmc, // Bulk-transfer-IN handler .fDataErrHandler = fUsbDataErr_Usbtmc, // Bulk-transfer error handler }; #endif // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // fUsbInit_Vendor() // VENDOR interface: initialize VENDOR bridge static int8_t fUsbInit_Vendor() { usbCtlApp_appIdx_Vendor = 0; const sUSBAppEntry_Control_t * app; foreach_ctl_app_vendor( app ) { int8_t ret = app->fUsbInit(); // "fUsbDeInit_Vendor -> fUsbInit_Vendor", Fixed: 08/07/19 if( ret != 0 ) return ret; } return 0; } // fUsbInit_Usbtmc() // USBTMC interface: initialize USBTMC bridge static int8_t fUsbInit_Usbtmc() { usbCtlApp_appIdx_Usbtmc = 0; { const sUSBAppEntry_Data_t * dataapp; foreachidx_data_app_usbtmc( dataapp, dataapp_idx ) { // deinitialize applications usbDataAppList_Usbtmc[ dataapp_idx ] = NULL; // data application must be registed in runtime } (void)dataapp; // register default data-application usbDataAppList_Usbtmc[ 0 ] = &usbapplication_default_dataapp; } { const sUSBAppEntry_Control_t * ctlapp; foreach_ctl_app_usbtmc( ctlapp ) { int8_t ret = ctlapp->fUsbInit(); if( ret != 0 ) return ret; } } return 0; } // ----------------------------------------------------------------------------- // fUsbDeInit_Vendor() // VENDOR interface: deinitialize VENDOR bridge static int8_t fUsbDeInit_Vendor() { usbCtlApp_appIdx_Vendor = 0; const sUSBAppEntry_Control_t * app; foreach_ctl_app_vendor( app ) { app->fUsbDeInit(); } return 0; } // fUsbDeInit_Usbtmc() // USBTMC interface: deinitialize USBTMC bridge static int8_t fUsbDeInit_Usbtmc() { usbCtlApp_appIdx_Usbtmc = 0; { const sUSBAppEntry_Control_t * app; foreach_ctl_app_usbtmc( app ) { app->fUsbDeInit(); } } { const sUSBAppEntry_Data_t * dataapp; foreachidx_data_app_usbtmc( dataapp, dataapp_idx ) { // destroy application pointer usbDataAppList_Usbtmc[ dataapp_idx ] = NULL; } (void)dataapp; } return 0; } // ----------------------------------------------------------------------------- // fUsbReset_Vendor() // VENDOR interface: USB-bus Reset handler static void fUsbReset_Vendor() { const sUSBAppEntry_Control_t * app; foreach_ctl_app_vendor( app ) { app->fResetEvent(); } } // fUsbReset_Usbtmc() // USBTMC interface: USB-bus Reset handler static void fUsbReset_Usbtmc() { const sUSBAppEntry_Control_t * app; foreach_ctl_app_usbtmc( app ) { app->fResetEvent(); } } // ----------------------------------------------------------------------------- // fUsbSetupRx_Vendor() // VENDOR interface: SETUP-packet interceptor static bool fUsbSetupRx_Vendor( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success ) { if( bFirstStage ) { const sUSBAppEntry_Control_t * app; foreachidx_ctl_app_vendor( app, idx ) { if( app->fUsbSetup( pSetup, bFirstStage, success ) ) { usbCtlApp_appIdx_Vendor = idx; return true; } } } usbCtlApp_appIdx_Vendor = 0; return false; } // ----------------------------------------------------------------------------- // fUsbSetupRx_Usbtmc() // USBTMC interface: SETUP-packet interceptor static bool fUsbSetupRx_Usbtmc( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success ) { if( bFirstStage ) { const sUSBAppEntry_Control_t * app; foreachidx_ctl_app_usbtmc( app, idx ) { if( app->fUsbSetup( pSetup, bFirstStage, success ) ) { usbCtlApp_appIdx_Usbtmc = idx; return true; } } } usbCtlApp_appIdx_Usbtmc = 0; return false; } // ----------------------------------------------------------------------------- // fUsbEp0Rx_Vendor() // VENDOR interface: Control-transfer-OUT handler static size_t fUsbEp0Rx_Vendor( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining ) { return usbCtlAppList_Vendor[ usbCtlApp_appIdx_Vendor ]->fUsbCtlEpRx( pSetup, rx, idx, bytesRemaining ); } // ----------------------------------------------------------------------------- // fUsbEp0Rx_Usbtmc() // USBTMC interface: Control-transfer-OUT handler static size_t fUsbEp0Rx_Usbtmc( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining ) { return usbCtlAppList_Usbtmc[ usbCtlApp_appIdx_Usbtmc ]->fUsbCtlEpRx( pSetup, rx, idx, bytesRemaining ); } // ----------------------------------------------------------------------------- // fUsbEp0Tx_Vendor() // VENDOR interface: Control-transfer-IN handler static size_t fUsbEp0Tx_Vendor( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ) { return usbCtlAppList_Vendor[ usbCtlApp_appIdx_Vendor ]->fUsbCtlEpTx( pSetup, tx, idx, bytesRemaining ); } // fUsbEp0Tx_Usbtmc() // USBTMC interface: Control-transfer-IN handler static size_t fUsbEp0Tx_Usbtmc( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining ) { return usbCtlAppList_Usbtmc[ usbCtlApp_appIdx_Usbtmc ]->fUsbCtlEpTx( pSetup, tx, idx, bytesRemaining ); } // ----------------------------------------------------------------------------- // fUsbSetInterface_Vendor() // VENDOR interface: USB-interface SetInterface request handler static bool fUsbSetInterface_Vendor( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc ) { if( (NULL != ifdesc) && USB_ACM_CONFIGURATION_VALUE == cfgidx && USB_ACM_INTERFACE_VALUE == ifdesc->bInterfaceNumber ) { return true; } return false; } // fUsbSetInterface_Usbtmc() // USBTMC interface: USB-interface SetInterface request handler static bool fUsbSetInterface_Usbtmc( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc ) { if( (NULL != ifdesc) && USB_TMC_CONFIGURATION_VALUE == cfgidx && USB_TMC_INTERFACE_VALUE == ifdesc->bInterfaceNumber ) { return true; } return false; } // ----------------------------------------------------------------------------- // fUsbClrInterface_Vendor() // VENDOR interface: USB-interface ClearInterface request handler static void fUsbClrInterface_Vendor( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc ) { if( (NULL != ifdesc) && USB_ACM_CONFIGURATION_VALUE == cfgidx && USB_ACM_INTERFACE_VALUE == ifdesc->bInterfaceNumber ) { return; } } // fUsbClrInterface_Usbtmc() // USBTMC interface: USB-interface ClearInterface request handler static void fUsbClrInterface_Usbtmc( uint8_t cfgidx, uint8_t ifidx, const sUSBInterfaceDescriptor_t * ifdesc ) { if( (NULL != ifdesc) && USB_TMC_CONFIGURATION_VALUE == cfgidx && USB_TMC_INTERFACE_VALUE == ifdesc->bInterfaceNumber ) { return; } } // ----------------------------------------------------------------------------- // fUsbDataRx_Usbtmc() // USBTMC interface: Data-Rx handler [Bulk-OUT-transfer] static bool fUsbDataRx_Usbtmc( uint8_t bEpLogAddress, sUSBTransfer_t * rx ) { const sUSBAppEntry_Data_t * app = NULL; with_data_app_for( bEpLogAddress, app ) { if( NULL != app->fDataRxHandler ) { return app->fDataRxHandler( bEpLogAddress, rx ); } } else with_default_data_app( bEpLogAddress, app ) { if( NULL != app->fDataRxHandler ) { return app->fDataRxHandler( bEpLogAddress, rx ); } } return false; } // fUsbDataTx_Usbtmc() // USBTMC interface: Data-Tx handler [Bulk-IN-transfer] // Is called after the first packet sent (need to call @usb_bridge_datain_beginsend) static bool fUsbDataTx_Usbtmc( uint8_t bEpLogAddress, sUSBTransfer_t * tx ) { const sUSBAppEntry_Data_t * app = NULL; with_data_app_for( bEpLogAddress, app ) { if( NULL != app->fDataTxHandler ) { return app->fDataTxHandler( bEpLogAddress, tx ); } } else with_default_data_app( bEpLogAddress, app ) { if( NULL != app->fDataTxHandler ) { return app->fDataTxHandler( bEpLogAddress, tx ); } } return false; } static bool fUsbDataErr_Usbtmc( uint8_t bEpLogAddress, uint32_t err ) { const sUSBAppEntry_Data_t * app = NULL; with_data_app_for( bEpLogAddress, app ) { if( NULL != app->fDataErrHandler ) { return app->fDataErrHandler( bEpLogAddress, err ); } } else with_default_data_app( bEpLogAddress, app ) { if( NULL != app->fDataErrHandler ) { return app->fDataErrHandler( bEpLogAddress, err ); } } return true; // true by default }