William Kane / Generic

Dependents:   LaserioLib

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers abcc_link.c Source File

abcc_link.c

00001 /*******************************************************************************
00002 ********************************************************************************
00003 **                                                                            **
00004 ** ABCC Driver version 4.01.01 (2015-12-14)                                   **
00005 **                                                                            **
00006 ** Delivered with:                                                            **
00007 **    ABP         7.16.01 (2015-10-14)                                        **
00008 **                                                                            */
00009 /*******************************************************************************
00010 ********************************************************************************
00011 ** COPYRIGHT NOTIFICATION (c) 2013 HMS Industrial Networks AB                 **
00012 **                                                                            **
00013 ** This code is the property of HMS Industrial Networks AB.                   **
00014 ** The source code may not be reproduced, distributed, or used without        **
00015 ** permission. When used together with a product from HMS, permission is      **
00016 ** granted to modify, reproduce and distribute the code in binary form        **
00017 ** without any restrictions.                                                  **
00018 **                                                                            **
00019 ** THE CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. HMS DOES NOT    **
00020 ** WARRANT THAT THE FUNCTIONS OF THE CODE WILL MEET YOUR REQUIREMENTS, OR     **
00021 ** THAT THE OPERATION OF THE CODE WILL BE UNINTERRUPTED OR ERROR-FREE, OR     **
00022 ** THAT DEFECTS IN IT CAN BE CORRECTED.                                       **
00023 ********************************************************************************
00024 ********************************************************************************
00025 ** File Description:
00026 ** Implements message queuing and write message flow control.
00027 **. and response handler functionality
00028 **
00029 ********************************************************************************
00030 ********************************************************************************
00031 */
00032 
00033 #include "abcc_drv_cfg.h"
00034 #include "abcc_td.h"
00035 #include "abcc_debug_err.h"
00036 #include "abcc_link.h"
00037 #include "abcc_drv_if.h"
00038 #include "abcc_mem.h"
00039 #include "abcc_sys_adapt.h"
00040 #include "abcc_timer.h"
00041 #include "abcc_handler.h"
00042 #include "abcc_port.h"
00043 
00044 /*******************************************************************************
00045 ** Constants
00046 ********************************************************************************
00047 */
00048 
00049 /*
00050 ** Max number of messages in each send queue.
00051 */
00052 #define LINK_MAX_NUM_CMDS_IN_Q            ABCC_CFG_MAX_NUM_APPL_CMDS
00053 #define LINK_MAX_NUM_RESP_IN_Q            ABCC_CFG_MAX_NUM_ABCC_CMDS
00054 
00055 /*
00056 ** Total number of message resources.
00057 */
00058 #define LINK_NUM_MSG_IN_POOL              ABCC_CFG_MAX_NUM_MSG_RESOURCES
00059 
00060 /*
00061 ** Max num message handlers for responses.
00062 ** The max number of outstanding commands counter is decremented
00063 ** before the handler is invoked therefore we need to handle 1 extra
00064 ** handler
00065 */
00066 #define LINK_MAX_NUM_MSG_HDL ( LINK_MAX_NUM_CMDS_IN_Q + 1 )
00067 
00068 
00069 /*******************************************************************************
00070 ** Typedefs
00071 ********************************************************************************
00072 */
00073 
00074 /*
00075 ** Message queue type for queueing cmds and responses.
00076 */
00077 typedef struct MsgQueueType
00078 {
00079    ABP_MsgType** queue;
00080    INT8 bReadIndex;
00081    INT8 bQueueSize;
00082    INT8 bNumInQueue;
00083 } MsgQueueType;
00084 
00085 
00086 /*******************************************************************************
00087 ** Public Globals
00088 ********************************************************************************
00089 */
00090 
00091 
00092 /*******************************************************************************
00093 ** Private Globals
00094 ********************************************************************************
00095 */
00096 
00097 /*
00098  * Largest supported message size.
00099  */
00100 static UINT16 link_iMaxMsgSize;
00101 
00102 /*
00103  ** Command and response queues
00104  */
00105 static ABP_MsgType* link_psCmds[LINK_MAX_NUM_CMDS_IN_Q ];
00106 static ABP_MsgType* link_psResponses[LINK_MAX_NUM_RESP_IN_Q];
00107 
00108 static MsgQueueType link_sCmdQueue;
00109 static MsgQueueType link_sRespQueue;
00110 
00111 /*
00112  ** Response handlers
00113  */
00114 static ABCC_MsgHandlerFuncType link_pnMsgHandler[ LINK_MAX_NUM_MSG_HDL ];
00115 static UINT8              link_bMsgSrcId[ LINK_MAX_NUM_MSG_HDL ];
00116 
00117 static ABCC_LinkNotifyIndType pnMsgSentHandler;
00118 static ABP_MsgType* link_psNotifyMsg;
00119 
00120 
00121 /*
00122  ** Max number of outstanding commands ( no received response yet )
00123  */
00124 static UINT8 link_bNumberOfOutstandingCommands = 0;
00125 
00126 /*******************************************************************************
00127 ** Private Services
00128 ********************************************************************************
00129 */
00130 static ABP_MsgType* link_DeQueue( MsgQueueType* psMsgQueue )
00131 {
00132    ABP_MsgType* psMsg = NULL;
00133    if ( psMsgQueue->bNumInQueue != 0 )
00134    {
00135       psMsg = psMsgQueue->queue[ psMsgQueue->bReadIndex++];
00136       psMsgQueue->bNumInQueue--;
00137       psMsgQueue->bReadIndex %= psMsgQueue->bQueueSize;
00138    }
00139    ABCC_ASSERT(psMsgQueue->bNumInQueue >= 0);
00140    return psMsg;
00141 }
00142 
00143 
00144 static BOOL link_EnQueue( MsgQueueType* psMsgQueue, ABP_MsgType* psMsg )
00145 {
00146    if ( psMsgQueue->bNumInQueue <  psMsgQueue->bQueueSize )
00147    {
00148       psMsgQueue->queue[  ( psMsgQueue->bNumInQueue + psMsgQueue->bReadIndex ) %  psMsgQueue->bQueueSize ] = psMsg;
00149       psMsgQueue->bNumInQueue++;
00150       return TRUE;
00151    }
00152    return FALSE;
00153 }
00154 
00155 static ABP_MsgType* link_Peek( MsgQueueType* psMsgQueue )
00156 {
00157    ABP_MsgType* psMsg;
00158 
00159    psMsg = NULL;
00160 
00161    if( psMsgQueue->bNumInQueue != 0 )
00162    {
00163       psMsg = psMsgQueue->queue[ psMsgQueue->bReadIndex ];
00164    }
00165 
00166    return( psMsg );
00167 }
00168 
00169 
00170 static void link_CheckNotification( const ABP_MsgType* const psMsg )
00171 {
00172    ABCC_DEBUG_MSG_DATA( "Msg sent", (ABP_MsgType*)psMsg );
00173    if( ( pnMsgSentHandler != NULL ) &&  ( psMsg == link_psNotifyMsg ) )
00174    {
00175       pnMsgSentHandler();
00176       pnMsgSentHandler = NULL;
00177    }
00178 }
00179 
00180 /*******************************************************************************
00181 ** Public Services
00182 ********************************************************************************
00183 */
00184 void ABCC_LinkInit( void )
00185 {
00186    UINT16 iCount;
00187    /*
00188    ** Init Queue structures.
00189    */
00190    link_sCmdQueue.bNumInQueue = 0;
00191    link_sCmdQueue.bQueueSize = LINK_MAX_NUM_CMDS_IN_Q;
00192    link_sCmdQueue.bReadIndex = 0;
00193    link_sCmdQueue.queue = link_psCmds;
00194 
00195    link_sRespQueue.bNumInQueue = 0;
00196    link_sRespQueue.bQueueSize = LINK_MAX_NUM_RESP_IN_Q;
00197    link_sRespQueue.bReadIndex = 0;
00198    link_sRespQueue.queue = link_psResponses;
00199 
00200    ABCC_MemCreatePool();
00201 
00202    for( iCount = 0; iCount < LINK_MAX_NUM_CMDS_IN_Q; iCount++  )
00203    {
00204       link_pnMsgHandler[ iCount ] = 0;
00205       link_bMsgSrcId[iCount ] = 0;
00206    }
00207 
00208    /*
00209    ** Initialize driver privates and states to default values.
00210    */
00211    link_bNumberOfOutstandingCommands = 0;
00212 
00213    pnMsgSentHandler = NULL;
00214    link_psNotifyMsg = NULL;
00215 
00216    link_iMaxMsgSize = ABCC_CFG_MAX_MSG_SIZE;
00217    /*
00218     ** Limit ABCC 30 messages to 255 bytes
00219     */
00220    if( ABCC_ReadModuleId() == ABP_MODULE_ID_ACTIVE_ABCC30 )
00221    {
00222       if ( link_iMaxMsgSize > ABP_MAX_MSG_255_DATA_BYTES )
00223       {
00224          link_iMaxMsgSize = ABP_MAX_MSG_255_DATA_BYTES;
00225       }
00226    }
00227 }
00228 
00229 
00230 ABP_MsgType* ABCC_LinkReadMessage( void )
00231 {
00232    ABCC_MsgType psReadMessage;
00233    ABCC_PORT_UseCritical();
00234 
00235    psReadMessage.psMsg = pnABCC_DrvReadMessage();
00236 
00237    if( psReadMessage.psMsg != NULL )
00238    {
00239       if( ( ABCC_GetLowAddrOct( psReadMessage.psMsg16->sHeader.iCmdReserved ) & ABP_MSG_HEADER_C_BIT ) == 0 )
00240       {
00241          /*
00242          ** Decrement number of outstanding commands if a response is received
00243          */
00244          ABCC_PORT_EnterCritical();
00245          link_bNumberOfOutstandingCommands--;
00246          ABCC_PORT_ExitCritical();
00247          ABCC_DEBUG_MSG_GENERAL( ( "Outstanding commands: %d\n",
00248                                  link_bNumberOfOutstandingCommands ) );
00249       }
00250    }
00251    return psReadMessage.psMsg;
00252 }
00253 
00254 
00255 void ABCC_LinkCheckSendMessage( void )
00256 {
00257    BOOL fCmdMsg;
00258    BOOL fMsgWritten;
00259    BOOL fSendMsg;
00260    ABP_MsgType* psWriteMessage = NULL;
00261 
00262    ABCC_PORT_UseCritical();
00263 
00264    fSendMsg = FALSE;
00265 
00266    ABCC_PORT_EnterCritical();
00267 
00268    /*
00269    ** Check if any messages are queued.
00270    ** If the queue index > 0 then there are messages in the qeueue.
00271    ** Response messages are prioritised before command messages.
00272    **
00273    ** Note: Only a reference to the message is retrieved from the queue before
00274    ** the transmission. It must stay in the queue until the transmission is
00275    ** completed to guarantee the thread protection that is implemented in
00276    ** ABCC_LinkWriteMessage().
00277    */
00278    if ( link_sRespQueue.bNumInQueue > 0 )
00279    {
00280       fCmdMsg = FALSE;
00281       fSendMsg = TRUE;
00282 
00283       psWriteMessage = link_Peek( &link_sRespQueue );
00284    }
00285    else if ( link_sCmdQueue.bNumInQueue > 0 )
00286    {
00287       fCmdMsg = TRUE;
00288       fSendMsg = TRUE;
00289 
00290       psWriteMessage = link_Peek( &link_sCmdQueue );
00291    }
00292 
00293    ABCC_PORT_ExitCritical();
00294 
00295    if ( fSendMsg && ( ( fCmdMsg && pnABCC_DrvISReadyForCmd() ) ||
00296                       ( !fCmdMsg && pnABCC_DrvISReadyForWriteMessage() ) ) )
00297    {
00298       fMsgWritten = pnABCC_DrvWriteMessage( psWriteMessage );
00299 
00300       /*
00301       ** The message has been transmitted, now it is time to dequeue it.
00302       */
00303       ABCC_PORT_EnterCritical();
00304 
00305       if( fCmdMsg )
00306       {
00307          link_DeQueue( &link_sCmdQueue );
00308          ABCC_DEBUG_MSG_EVENT( "Command dequeued", psWriteMessage );
00309          ABCC_DEBUG_MSG_GENERAL( ( "CmdQ status: %d(%d)\n", link_sCmdQueue.bNumInQueue, link_sCmdQueue.bQueueSize ) );
00310       }
00311       else
00312       {
00313          link_DeQueue( &link_sRespQueue );
00314          ABCC_DEBUG_MSG_EVENT( "Response dequeued", psWriteMessage );
00315          ABCC_DEBUG_MSG_GENERAL( ( "RespQ status: %d(%d)\n", link_sRespQueue.bNumInQueue, link_sRespQueue.bQueueSize ) );
00316       }
00317 
00318       ABCC_PORT_ExitCritical();
00319 
00320       if( fMsgWritten )
00321       {
00322          /*
00323          ** The message was successfully written and can be deallocated now.
00324          */
00325          link_CheckNotification( psWriteMessage );
00326          ABCC_LinkFree( &psWriteMessage );
00327       }
00328    }
00329 }
00330 
00331 
00332 void ABCC_LinkRunDriverRx( void )
00333 {
00334    ABP_MsgType* psSentMsg;
00335 
00336    psSentMsg = pnABCC_DrvRunDriverRx();
00337    /*
00338    ** If a write message was sent, free the buffer.
00339    */
00340    if( psSentMsg )
00341    {
00342       link_CheckNotification( psSentMsg );
00343       ABCC_LinkFree( &psSentMsg );
00344    }
00345 }
00346 
00347 
00348 UINT16 ABCC_LinkGetNumCmdQueueEntries( void )
00349 {
00350    UINT16 iQEntries;
00351    iQEntries =  LINK_MAX_NUM_CMDS_IN_Q - link_bNumberOfOutstandingCommands;
00352    return iQEntries;
00353 }
00354 
00355 
00356 ABCC_ErrorCodeType ABCC_LinkWriteMessage( ABP_MsgType* psWriteMsg )
00357 {
00358    BOOL fSendMsg;
00359    ABCC_MsgType uWriteMsg;
00360    BOOL fMsgWritten;
00361    BOOL fCmdMsg;
00362    ABCC_ErrorCodeType eErrorCode;
00363    UINT32 lAddErrorInfo;
00364 
00365    ABCC_PORT_UseCritical();
00366 
00367    eErrorCode = ABCC_EC_NO_ERROR;
00368    lAddErrorInfo = 0;
00369 
00370    fSendMsg = FALSE;
00371    uWriteMsg.psMsg = psWriteMsg;
00372 
00373    if( iLeTOi( psWriteMsg->sHeader.iDataSize ) > link_iMaxMsgSize )
00374    {
00375       eErrorCode = ABCC_EC_WRMSG_SIZE_ERR;
00376       ABCC_CbfDriverError( ABCC_SEV_WARNING, eErrorCode,
00377                            iLeTOi( psWriteMsg->sHeader.iDataSize ) );
00378       return( eErrorCode );
00379    }
00380 
00381    ABCC_PORT_EnterCritical();
00382 
00383    /*
00384    ** Check if there are any messages already queued. If both queues are empty
00385    ** that means there is no ongoing transmission and this message can be
00386    ** transmitted right now. If any of the queues are populated there is an
00387    ** ongoing transmission, in this case only queue the message.
00388    */
00389    if( ( link_sCmdQueue.bNumInQueue == 0 ) && ( link_sRespQueue.bNumInQueue == 0 ) )
00390    {
00391       fSendMsg = TRUE;
00392    }
00393 
00394    /*
00395    ** Always queue the message even if it can be transmitted directly. This is
00396    ** the lock to inhibit other threads to interrupt the ongoing transmission.
00397    */
00398    if( ABCC_GetLowAddrOct( uWriteMsg.psMsg16->sHeader.iCmdReserved ) & ABP_MSG_HEADER_C_BIT )
00399    {
00400       fCmdMsg = TRUE;
00401 
00402       if( LINK_MAX_NUM_CMDS_IN_Q == link_bNumberOfOutstandingCommands )
00403       {
00404          fSendMsg = FALSE;
00405          lAddErrorInfo = (UINT32)link_bNumberOfOutstandingCommands;
00406          eErrorCode = ABCC_EC_LINK_CMD_QUEUE_FULL;
00407       }
00408       else if( link_EnQueue(&link_sCmdQueue, psWriteMsg ) )
00409       {
00410          ABCC_DEBUG_MSG_EVENT( "Command queued", psWriteMsg  );
00411          ABCC_DEBUG_MSG_GENERAL( ( "CmdQ status: %d(%d)\n", link_sCmdQueue.bNumInQueue, link_sCmdQueue.bQueueSize ) );
00412 
00413          ABCC_MemSetBufferStatus( psWriteMsg, ABCC_MEM_BUFSTAT_SENT );
00414          link_bNumberOfOutstandingCommands++;
00415          ABCC_DEBUG_MSG_GENERAL( ( "Outstanding commands: %d\n", link_bNumberOfOutstandingCommands ) );
00416       }
00417       else
00418       {
00419          ABCC_DEBUG_MSG_EVENT("Command queue full", psWriteMsg );
00420          ABCC_DEBUG_MSG_GENERAL( ( "CmdQ status: %d(%d)\n", link_sCmdQueue.bNumInQueue, link_sCmdQueue.bQueueSize ) );
00421          fSendMsg = FALSE;
00422          eErrorCode = ABCC_EC_LINK_CMD_QUEUE_FULL;
00423          ABCC_ASSERT( FALSE );
00424       }
00425    }
00426    else
00427    {
00428       fCmdMsg = FALSE;
00429 
00430       if( link_EnQueue( &link_sRespQueue, psWriteMsg ) )
00431       {
00432          ABCC_DEBUG_MSG_EVENT("Response msg queued ", psWriteMsg );
00433          ABCC_DEBUG_MSG_GENERAL( ( "RespQ status: %d(%d)\n", link_sRespQueue.bNumInQueue, link_sRespQueue.bQueueSize ) );
00434          ABCC_MemSetBufferStatus( psWriteMsg, ABCC_MEM_BUFSTAT_SENT );
00435       }
00436       else
00437       {
00438          ABCC_DEBUG_MSG_EVENT("Response queue full", psWriteMsg );
00439          ABCC_DEBUG_MSG_GENERAL( ( "RespQ status: %d(%d)\n", link_sRespQueue.bNumInQueue, link_sRespQueue.bQueueSize ) );
00440          fSendMsg = FALSE;
00441          eErrorCode = ABCC_EC_LINK_RESP_QUEUE_FULL;
00442          lAddErrorInfo = (UINT32)psWriteMsg;
00443       }
00444    }
00445 
00446    ABCC_PORT_ExitCritical();
00447 
00448    /*
00449    ** Continue the transmission of the message if both queues were empty.
00450    ** Else the message will be transmitted at the next ABCC write message event.
00451    */
00452    if( fSendMsg && ( ( fCmdMsg && pnABCC_DrvISReadyForCmd() ) ||
00453                      ( !fCmdMsg && pnABCC_DrvISReadyForWriteMessage() ) ) )
00454    {
00455       fMsgWritten = pnABCC_DrvWriteMessage( psWriteMsg );
00456 
00457       ABCC_PORT_EnterCritical();
00458 
00459       /*
00460       ** The message has been transmitted, now it is time to dequeue it.
00461       */
00462       if( fCmdMsg )
00463       {
00464          link_DeQueue( &link_sCmdQueue );
00465          ABCC_DEBUG_MSG_EVENT( "Command dequeued", psWriteMsg );
00466          ABCC_DEBUG_MSG_GENERAL( ( "CmdQ status: %d(%d)\n", link_sCmdQueue.bNumInQueue, link_sCmdQueue.bQueueSize ) );
00467       }
00468       else
00469       {
00470          link_DeQueue( &link_sRespQueue );
00471          ABCC_DEBUG_MSG_EVENT( "Response dequeued", psWriteMsg );
00472          ABCC_DEBUG_MSG_GENERAL( ( "RespQ status: %d(%d)\n", link_sRespQueue.bNumInQueue, link_sRespQueue.bQueueSize ) );
00473       }
00474 
00475       ABCC_PORT_ExitCritical();
00476 
00477       if( fMsgWritten )
00478       {
00479          /*
00480          ** The message was successfully written and can be deallocated now.
00481          */
00482          link_CheckNotification( psWriteMsg );
00483          ABCC_LinkFree( &psWriteMsg );
00484       }
00485    }
00486 
00487    if( eErrorCode != ABCC_EC_NO_ERROR )
00488    {
00489       ABCC_CbfDriverError( ABCC_SEV_WARNING, eErrorCode, lAddErrorInfo );
00490    }
00491 
00492    return( eErrorCode );
00493 }
00494 
00495 ABCC_ErrorCodeType ABCC_LinkWrMsgWithNotification( ABP_MsgType* psWriteMsg,
00496                                                    ABCC_LinkNotifyIndType pnHandler )
00497 {
00498    ABCC_ErrorCodeType eResult;
00499 
00500    /*
00501    ** Save callback function to call when message is successfully sent.
00502    */
00503    ABCC_ASSERT( pnMsgSentHandler == NULL );
00504    pnMsgSentHandler = pnHandler;
00505    link_psNotifyMsg = psWriteMsg;
00506 
00507    eResult = ABCC_LinkWriteMessage( psWriteMsg );
00508 
00509    return( eResult );
00510 }
00511 
00512 void ABCC_LinkFree( ABP_MsgType** ppsBuffer )
00513 {
00514    ABCC_ASSERT_ERR( *ppsBuffer != 0, ABCC_SEV_WARNING, ABCC_EC_TRYING_TO_FREE_NULL_POINTER, 0 );
00515 
00516    ABCC_MemFree( ppsBuffer );
00517 }
00518 
00519 ABCC_ErrorCodeType ABCC_LinkMapMsgHandler( UINT8 bSrcId, ABCC_MsgHandlerFuncType  pnMSgHandler )
00520 {
00521    UINT16 iIndex;
00522    ABCC_ErrorCodeType eResult = ABCC_EC_NO_RESOURCES;
00523    ABCC_PORT_UseCritical();
00524 
00525    /*
00526    ** Find free spot.
00527    */
00528    ABCC_PORT_EnterCritical();
00529    for ( iIndex = 0; iIndex < LINK_MAX_NUM_MSG_HDL ; iIndex++ )
00530    {
00531       if (link_pnMsgHandler[ iIndex ] == 0 )
00532       {
00533          link_pnMsgHandler[ iIndex ] = pnMSgHandler;
00534          link_bMsgSrcId[ iIndex ] = bSrcId;
00535          eResult = ABCC_EC_NO_ERROR;
00536          break;
00537       }
00538    }
00539    ABCC_PORT_ExitCritical();
00540    return( eResult );
00541 }
00542 
00543 ABCC_MsgHandlerFuncType  ABCC_LinkGetMsgHandler( UINT8 bSrcId )
00544 {
00545    UINT16 iIndex;
00546    ABCC_MsgHandlerFuncType pnHandler = NULL;
00547    ABCC_PORT_UseCritical();
00548 
00549    /*
00550    ** Find message handler. If not found return NULL.
00551    */
00552    ABCC_PORT_EnterCritical();
00553    for ( iIndex = 0; iIndex < LINK_MAX_NUM_MSG_HDL ; iIndex++ )
00554    {
00555       if ( ( link_pnMsgHandler[ iIndex ] != NULL ) && ( link_bMsgSrcId[ iIndex ] == bSrcId ) )
00556       {
00557          pnHandler = link_pnMsgHandler[ iIndex ];
00558          link_pnMsgHandler[ iIndex ] = NULL;
00559          break;
00560       }
00561    }
00562    ABCC_PORT_ExitCritical();
00563    return pnHandler;
00564 }
00565 
00566 BOOL ABCC_LinkIsSrcIdUsed( UINT8 bSrcId )
00567 {
00568    BOOL fFound = FALSE;
00569    UINT16 iIndex;
00570 
00571    for ( iIndex = 0; iIndex < LINK_MAX_NUM_MSG_HDL ; iIndex++ )
00572    {
00573       if ( ( link_pnMsgHandler[ iIndex ] != NULL ) && ( link_bMsgSrcId[ iIndex ] == bSrcId ) )
00574       {
00575          fFound = TRUE;
00576          break;
00577       }
00578    }
00579    return fFound;
00580 }