2019-09-14 12:13:11 -04:00
/*
* The MIT License ( MIT )
*
2019-09-18 21:31:38 -04:00
* Copyright ( c ) 2019 Nathan Conrad
2019-09-14 12:13:11 -04:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*
*/
# include <strings.h>
2019-09-18 23:53:28 -04:00
# include <stdlib.h> /* atoi */
2019-09-19 20:08:45 -04:00
# include "tusb.h"
2019-09-14 21:24:52 -04:00
# include "bsp/board.h"
2019-09-14 18:07:12 -04:00
# include "main.h"
2019-09-14 12:13:11 -04:00
2019-09-25 11:34:27 -04:00
# if (CFG_TUD_USBTMC_ENABLE_488)
2019-09-14 12:13:11 -04:00
usbtmc_response_capabilities_488_t const
# else
usbtmc_response_capabilities_t const
# endif
2019-09-19 20:08:45 -04:00
tud_usbtmc_app_capabilities =
2019-09-14 12:13:11 -04:00
{
. USBTMC_status = USBTMC_STATUS_SUCCESS ,
. bcdUSBTMC = USBTMC_VERSION ,
. bmIntfcCapabilities =
{
. listenOnly = 0 ,
. talkOnly = 0 ,
2019-09-14 18:07:12 -04:00
. supportsIndicatorPulse = 1
2019-09-14 12:13:11 -04:00
} ,
. bmDevCapabilities = {
. canEndBulkInOnTermChar = 0
} ,
2019-09-25 11:34:27 -04:00
# if (CFG_TUD_USBTMC_ENABLE_488)
2019-09-14 12:13:11 -04:00
. bcdUSB488 = USBTMC_488_VERSION ,
. bmIntfcCapabilities488 =
{
2019-09-14 16:56:53 -04:00
. supportsTrigger = 1 ,
2019-09-14 12:13:11 -04:00
. supportsREN_GTL_LLO = 0 ,
. is488_2 = 1
} ,
. bmDevCapabilities488 =
{
. SCPI = 1 ,
. SR1 = 0 ,
. RL1 = 0 ,
. DT1 = 0 ,
}
# endif
} ;
2019-09-19 16:43:59 -04:00
# define IEEE4882_STB_QUESTIONABLE (0x08u)
# define IEEE4882_STB_MAV (0x10u)
# define IEEE4882_STB_SER (0x20u)
# define IEEE4882_STB_SRQ (0x40u)
2019-09-18 19:24:54 -04:00
static const char idn [ ] = " TinyUSB,ModelNumber,SerialNumber,FirmwareVer123456 \r \n " ;
//static const char idn[] = "TinyUSB,ModelNumber,SerialNumber,FirmwareVer and a bunch of other text to make it longer than a packet, perhaps? lets make it three transfers...\n";
2019-09-14 21:24:52 -04:00
static volatile uint8_t status ;
2019-09-14 12:13:11 -04:00
2019-09-14 21:24:52 -04:00
// 0=not query, 1=queried, 2=delay,set(MAV), 3=delay 4=ready?
// (to simulate delay)
static volatile uint16_t queryState = 0 ;
static volatile uint32_t queryDelayStart ;
static volatile uint32_t bulkInStarted ;
2019-09-18 21:31:38 -04:00
static volatile uint32_t idnQuery ;
2019-09-18 23:53:28 -04:00
static uint32_t resp_delay = 125u ; // Adjustable delay, to allow for better testing
2019-09-18 21:31:38 -04:00
static size_t buffer_len ;
2019-09-21 21:46:46 -04:00
static size_t buffer_tx_ix ; // for transmitting using multiple transfers
2019-09-18 21:31:38 -04:00
static uint8_t buffer [ 225 ] ; // A few packets long should be enough.
2019-09-14 21:24:52 -04:00
static usbtmc_msg_dev_dep_msg_in_header_t rspMsg = {
. bmTransferAttributes =
{
. EOM = 1 ,
. UsingTermChar = 0
}
} ;
2019-09-14 12:13:11 -04:00
2019-09-24 13:42:29 -04:00
void tud_usbtmc_app_open_cb ( uint8_t interface_id )
2019-09-24 13:11:45 -04:00
{
( void ) interface_id ;
2019-09-25 11:34:27 -04:00
tud_usbtmc_start_bus_read ( ) ;
2019-09-24 13:11:45 -04:00
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_msg_trigger_cb ( usbtmc_msg_generic_t * msg ) {
2019-09-18 21:31:38 -04:00
( void ) msg ;
2019-09-19 16:43:59 -04:00
// Let trigger set the SRQ
status | = IEEE4882_STB_SRQ ;
2019-09-14 12:13:11 -04:00
return true ;
}
2019-09-18 21:31:38 -04:00
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_msgBulkOut_start_cb ( usbtmc_msg_request_dev_dep_out const * msgHeader )
2019-09-18 21:31:38 -04:00
{
( void ) msgHeader ;
buffer_len = 0 ;
2019-09-21 21:46:46 -04:00
if ( msgHeader - > TransferSize > sizeof ( buffer ) )
{
return false ;
}
2019-09-14 16:56:53 -04:00
return true ;
}
2019-09-14 12:13:11 -04:00
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_msg_data_cb ( void * data , size_t len , bool transfer_complete )
2019-09-14 12:13:11 -04:00
{
2019-09-14 22:55:42 -04:00
// If transfer isn't finished, we just ignore it (for now)
2019-09-18 21:31:38 -04:00
if ( len + buffer_len < sizeof ( buffer ) )
{
memcpy ( & ( buffer [ buffer_len ] ) , data , len ) ;
buffer_len + = len ;
}
2019-09-21 21:46:46 -04:00
else
{
return false ; // buffer overflow!
}
2019-09-18 21:31:38 -04:00
queryState = transfer_complete ;
idnQuery = 0 ;
if ( transfer_complete & & ( len > = 4 ) & & ! strncasecmp ( " *idn? " , data , 4 ) )
{
idnQuery = 1 ;
2019-09-14 12:13:11 -04:00
}
2019-09-18 23:53:28 -04:00
if ( transfer_complete & & ! strncasecmp ( " delay " , data , 5 ) )
{
queryState = 0 ;
2019-09-19 16:43:59 -04:00
int d = atoi ( ( char * ) data + 5 ) ;
if ( d > 10000 )
d = 10000 ;
if ( d < 0 )
d = 0 ;
resp_delay = ( uint32_t ) d ;
2019-09-18 23:53:28 -04:00
}
2019-09-25 11:34:27 -04:00
tud_usbtmc_start_bus_read ( ) ;
2019-09-14 12:13:11 -04:00
return true ;
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_msgBulkIn_complete_cb ( )
2019-09-14 12:13:11 -04:00
{
2019-09-21 21:46:46 -04:00
if ( ( buffer_tx_ix = = buffer_len ) | | idnQuery ) // done
{
status & = ( uint8_t ) ~ ( IEEE4882_STB_MAV ) ; // clear MAV
queryState = 0 ;
bulkInStarted = 0 ;
buffer_tx_ix = 0 ;
}
2019-09-25 11:34:27 -04:00
tud_usbtmc_start_bus_read ( ) ;
2019-09-14 22:55:42 -04:00
2019-09-14 12:13:11 -04:00
return true ;
}
2019-09-17 13:26:10 -04:00
static unsigned int msgReqLen ;
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_msgBulkIn_request_cb ( usbtmc_msg_request_dev_dep_in const * request )
2019-09-14 12:13:11 -04:00
{
2019-09-14 21:24:52 -04:00
rspMsg . header . MsgID = request - > header . MsgID ,
rspMsg . header . bTag = request - > header . bTag ,
rspMsg . header . bTagInverse = request - > header . bTagInverse ;
2019-09-17 13:26:10 -04:00
msgReqLen = request - > TransferSize ;
2019-09-21 21:46:46 -04:00
2019-09-18 21:31:38 -04:00
# ifdef xDEBUG
uart_tx_str_sync ( " MSG_IN_DATA: Requested! \r \n " ) ;
# endif
2019-09-21 21:46:46 -04:00
if ( queryState = = 0 | | ( buffer_tx_ix = = 0 ) )
{
TU_ASSERT ( bulkInStarted = = 0 ) ;
bulkInStarted = 1 ;
2019-09-14 22:55:42 -04:00
2019-09-21 21:46:46 -04:00
// > If a USBTMC interface receives a Bulk-IN request prior to receiving a USBTMC command message
// that expects a response, the device must NAK the request (*not stall*)
}
else
{
size_t txlen = tu_min32 ( buffer_len - buffer_tx_ix , msgReqLen ) ;
2019-09-25 11:34:27 -04:00
tud_usbtmc_transmit_dev_msg_data ( & buffer [ buffer_tx_ix ] , txlen ,
2019-09-21 21:46:46 -04:00
( buffer_tx_ix + txlen ) = = buffer_len , false ) ;
buffer_tx_ix + = txlen ;
}
2019-09-14 21:24:52 -04:00
// Always return true indicating not to stall the EP.
2019-09-14 12:13:11 -04:00
return true ;
}
2019-09-14 21:24:52 -04:00
void usbtmc_app_task_iter ( void ) {
switch ( queryState ) {
2019-09-15 14:57:02 -04:00
case 0 :
break ;
2019-09-14 21:24:52 -04:00
case 1 :
queryDelayStart = board_millis ( ) ;
queryState = 2 ;
break ;
case 2 :
2019-09-18 23:53:28 -04:00
if ( ( board_millis ( ) - queryDelayStart ) > resp_delay ) {
2019-09-14 21:24:52 -04:00
queryDelayStart = board_millis ( ) ;
queryState = 3 ;
status | = 0x10u ; // MAV
2019-09-18 21:31:38 -04:00
status | = 0x40u ; // SRQ
2019-09-14 21:24:52 -04:00
}
break ;
case 3 :
2019-09-18 23:53:28 -04:00
if ( ( board_millis ( ) - queryDelayStart ) > resp_delay ) {
2019-09-14 21:24:52 -04:00
queryState = 4 ;
}
break ;
case 4 : // time to transmit;
2019-09-21 21:46:46 -04:00
if ( bulkInStarted & & ( buffer_tx_ix = = 0 ) ) {
2019-09-18 21:31:38 -04:00
if ( idnQuery )
{
2019-09-25 11:34:27 -04:00
tud_usbtmc_transmit_dev_msg_data ( idn , tu_min32 ( sizeof ( idn ) - 1 , msgReqLen ) , true , false ) ;
2019-09-21 21:46:46 -04:00
queryState = 0 ;
bulkInStarted = 0 ;
2019-09-18 21:31:38 -04:00
}
else
{
2019-09-21 21:46:46 -04:00
buffer_tx_ix = tu_min32 ( buffer_len , msgReqLen ) ;
2019-09-25 11:34:27 -04:00
tud_usbtmc_transmit_dev_msg_data ( buffer , buffer_tx_ix , buffer_tx_ix = = buffer_len , false ) ;
2019-09-18 21:31:38 -04:00
}
2019-09-14 22:55:42 -04:00
// MAV is cleared in the transfer complete callback.
2019-09-14 21:24:52 -04:00
}
break ;
2019-09-14 22:55:42 -04:00
default :
TU_ASSERT ( false , ) ;
return ;
2019-09-14 21:24:52 -04:00
}
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_initiate_clear_cb ( uint8_t * tmcResult )
2019-09-15 14:57:02 -04:00
{
2019-09-14 22:55:42 -04:00
* tmcResult = USBTMC_STATUS_SUCCESS ;
2019-09-15 14:57:02 -04:00
queryState = 0 ;
bulkInStarted = false ;
status = 0 ;
2019-09-14 22:55:42 -04:00
return true ;
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_check_clear_cb ( usbtmc_get_clear_status_rsp_t * rsp )
2019-09-15 14:57:02 -04:00
{
queryState = 0 ;
bulkInStarted = false ;
status = 0 ;
2019-09-24 13:11:45 -04:00
buffer_tx_ix = 0u ;
buffer_len = 0u ;
2019-09-14 22:55:42 -04:00
rsp - > USBTMC_status = USBTMC_STATUS_SUCCESS ;
rsp - > bmClear . BulkInFifoBytes = 0u ;
return true ;
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_initiate_abort_bulk_in_cb ( uint8_t * tmcResult )
2019-09-18 19:24:54 -04:00
{
bulkInStarted = 0 ;
* tmcResult = USBTMC_STATUS_SUCCESS ;
return true ;
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_check_abort_bulk_in_cb ( usbtmc_check_abort_bulk_rsp_t * rsp )
2019-09-18 19:24:54 -04:00
{
2019-09-19 16:43:59 -04:00
( void ) rsp ;
2019-09-25 11:34:27 -04:00
tud_usbtmc_start_bus_read ( ) ;
2019-09-18 19:24:54 -04:00
return true ;
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_initiate_abort_bulk_out_cb ( uint8_t * tmcResult )
2019-09-18 19:24:54 -04:00
{
* tmcResult = USBTMC_STATUS_SUCCESS ;
return true ;
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_check_abort_bulk_out_cb ( usbtmc_check_abort_bulk_rsp_t * rsp )
2019-09-18 19:24:54 -04:00
{
2019-09-19 16:43:59 -04:00
( void ) rsp ;
2019-09-25 11:34:27 -04:00
tud_usbtmc_start_bus_read ( ) ;
2019-09-18 19:24:54 -04:00
return true ;
}
2019-09-17 13:26:10 -04:00
2019-09-25 11:34:27 -04:00
void tud_usbtmc_app_bulkIn_clearFeature_cb ( void )
2019-09-15 14:57:02 -04:00
{
}
2019-09-25 11:34:27 -04:00
void tud_usmtmc_app_bulkOut_clearFeature_cb ( void )
2019-09-15 14:57:02 -04:00
{
2019-09-25 11:34:27 -04:00
tud_usbtmc_start_bus_read ( ) ;
2019-09-15 14:57:02 -04:00
}
2019-09-14 22:55:42 -04:00
2019-09-14 12:13:11 -04:00
// Return status byte, but put the transfer result status code in the rspResult argument.
2019-09-24 13:42:29 -04:00
uint8_t tud_usbtmc_app_get_stb_cb ( uint8_t * tmcResult )
2019-09-14 12:13:11 -04:00
{
2019-09-18 21:31:38 -04:00
uint8_t old_status = status ;
2019-09-19 16:43:59 -04:00
status = ( uint8_t ) ( status & ~ ( IEEE4882_STB_SRQ ) ) ; // clear SRQ
2019-09-18 21:31:38 -04:00
2019-09-14 21:24:52 -04:00
* tmcResult = USBTMC_STATUS_SUCCESS ;
2019-09-14 12:13:11 -04:00
// Increment status so that we see different results on each read...
2019-09-18 21:31:38 -04:00
return old_status ;
2019-09-14 12:13:11 -04:00
}
2019-09-24 13:42:29 -04:00
bool tud_usbtmc_app_indicator_pulse_cb ( tusb_control_request_t const * msg , uint8_t * tmcResult )
2019-09-14 18:07:12 -04:00
{
2019-09-14 21:24:52 -04:00
( void ) msg ;
2019-09-14 18:07:12 -04:00
led_indicator_pulse ( ) ;
2019-09-14 21:24:52 -04:00
* tmcResult = USBTMC_STATUS_SUCCESS ;
return true ;
2019-09-14 18:07:12 -04:00
}