Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 }
Generated on Tue Jul 12 2022 15:51:56 by
