1 //<MStar Software>
2 //******************************************************************************
3 // MStar Software
4 // Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
5 // All software, firmware and related documentation herein ("MStar Software") are
6 // intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
7 // law, including, but not limited to, copyright law and international treaties.
8 // Any use, modification, reproduction, retransmission, or republication of all
9 // or part of MStar Software is expressly prohibited, unless prior written
10 // permission has been granted by MStar.
11 //
12 // By accessing, browsing and/or using MStar Software, you acknowledge that you
13 // have read, understood, and agree, to be bound by below terms ("Terms") and to
14 // comply with all applicable laws and regulations:
15 //
16 // 1. MStar shall retain any and all right, ownership and interest to MStar
17 // Software and any modification/derivatives thereof.
18 // No right, ownership, or interest to MStar Software and any
19 // modification/derivatives thereof is transferred to you under Terms.
20 //
21 // 2. You understand that MStar Software might include, incorporate or be
22 // supplied together with third party`s software and the use of MStar
23 // Software may require additional licenses from third parties.
24 // Therefore, you hereby agree it is your sole responsibility to separately
25 // obtain any and all third party right and license necessary for your use of
26 // such third party`s software.
27 //
28 // 3. MStar Software and any modification/derivatives thereof shall be deemed as
29 // MStar`s confidential information and you agree to keep MStar`s
30 // confidential information in strictest confidence and not disclose to any
31 // third party.
32 //
33 // 4. MStar Software is provided on an "AS IS" basis without warranties of any
34 // kind. Any warranties are hereby expressly disclaimed by MStar, including
35 // without limitation, any warranties of merchantability, non-infringement of
36 // intellectual property rights, fitness for a particular purpose, error free
37 // and in conformity with any international standard. You agree to waive any
38 // claim against MStar for any loss, damage, cost or expense that you may
39 // incur related to your use of MStar Software.
40 // In no event shall MStar be liable for any direct, indirect, incidental or
41 // consequential damages, including without limitation, lost of profit or
42 // revenues, lost or damage of data, and unauthorized system use.
43 // You agree that this Section 4 shall still apply without being affected
44 // even if MStar Software has been modified by MStar in accordance with your
45 // request or instruction for your use, except otherwise agreed by both
46 // parties in writing.
47 //
48 // 5. If requested, MStar may from time to time provide technical supports or
49 // services in relation with MStar Software to you for your use of
50 // MStar Software in conjunction with your or your customer`s product
51 // ("Services").
52 // You understand and agree that, except otherwise agreed by both parties in
53 // writing, Services are provided on an "AS IS" basis and the warranty
54 // disclaimer set forth in Section 4 above shall apply.
55 //
56 // 6. Nothing contained herein shall be construed as by implication, estoppels
57 // or otherwise:
58 // (a) conferring any license or right to use MStar name, trademark, service
59 // mark, symbol or any other identification;
60 // (b) obligating MStar or any of its affiliates to furnish any person,
61 // including without limitation, you and your customers, any assistance
62 // of any kind whatsoever, or any information; or
63 // (c) conferring any license or right under any intellectual property right.
64 //
65 // 7. These terms shall be governed by and construed in accordance with the laws
66 // of Taiwan, R.O.C., excluding its conflict of law rules.
67 // Any and all dispute arising out hereof or related hereto shall be finally
68 // settled by arbitration referred to the Chinese Arbitration Association,
69 // Taipei in accordance with the ROC Arbitration Law and the Arbitration
70 // Rules of the Association by three (3) arbitrators appointed in accordance
71 // with the said Rules.
72 // The place of arbitration shall be in Taipei, Taiwan and the language shall
73 // be English.
74 // The arbitration award shall be final and binding to both parties.
75 //
76 //******************************************************************************
77 //<MStar Software>
78 /*******************************************************************************
79 Shared library to log data to a circular buffer and output the data to
80 multiple devices.
81 *******************************************************************************/
82 #if defined (MSOS_TYPE_LINUX)
83 #include <stdio.h>
84
85 #include <pthread.h>
86
87 #include <errno.h>
88 #include <assert.h>
89 #include <sys/time.h>
90 #include <sys/types.h>
91 #include <sys/syscall.h>
92
93 #include "frhsl_datalink.h"
94 #include "frhsl_ringbuffer.h"
95 #include "frhsl_cfg.h"
96 #include "apiHSL.h"
97 #include "frhsl_RAWLOB.h"
98 #include "MsCommon.h"
99 #include "drvWDT.h"
100
101 // large part of the data are bookmarks (8 * BUFFER_SEGMENTS_COUNT)
102 #define SYS_STATE_BUFSIZE (1024)
103
104
105 #define DUMP_LP_LEN 41
106 static MS_U8 s_DumpBufferLP[] = {0x17,
107 0x13, 0x0F, 0x09, 0x00, 0x00,
108 0x13, 0x0F, 0x09, 0x00, 0x00,
109 0x13, 0x0F, 0x09, 0x00, 0x00,
110 0x13, 0x0F, 0x09, 0x00, 0x00,
111 0x13, 0x0F, 0x09, 0x00, 0x00,
112 0x12, 0x03, 0xFF, 0x00, 0x00, 0x11, 0x02, 0x00, 0x11, 0x3B, 0xD0, 0x10, 0x00, 0x00, 0x17};
113 static MS_U8 s_CriticalDumpBufferLP[] = {0x17,
114 0x13, 0x0F, 0x09, 0x00, 0x00,
115 0x13, 0x0F, 0x09, 0x00, 0x00,
116 0x13, 0x0F, 0x09, 0x00, 0x00,
117 0x13, 0x0F, 0x09, 0x00, 0x00,
118 0x13, 0x0F, 0x09, 0x00, 0x00,
119 0x12, 0x03, 0xFF, 0x00, 0x00, 0x11, 0x02, 0x00, 0x11, 0x59, 0x86, 0x10, 0x00, 0x00, 0x17};
120
121 ST_LIBRARY_SHORT_INFO gDynamicLibraryInfo[HSL_MAX_LIBRARY_COUNT];
122 MS_U16 gDynamicLibraryCount = 0;
123 ST_THREAD_INFO gThreadInfo[HSL_MAX_THREAD_COUNT];
124 MS_U16 gThreadCount = 0;
125
126 pthread_t gTestThreads[MAX_SELFTEST_THREAD_CNT];
127 MS_BOOL gRunLoadTest = true;
128
HslSelfTestThreadFun(void * pArg)129 void *HslSelfTestThreadFun(void* pArg)
130 {
131 struct timeval timeStart, timeNow;
132 int i = 0;
133 ST_HSL_SELFTEST_CMD command;
134 ST_HSL_SELFTEST_CMD* pCommand = &command;
135 memcpy(pCommand, pArg, sizeof(ST_HSL_SELFTEST_CMD));
136
137 gettimeofday(&timeStart, 0);
138 timeNow = timeStart;
139
140 while( gRunLoadTest &&
141 ((timeNow.tv_sec-timeStart.tv_sec)*1000000 + (timeNow.tv_usec-timeStart.tv_usec) < (pCommand->mRunTime*1000000)) )
142 {
143 for(i=0; i < pCommand->mCntSimpleLP; i++)
144 {
145 M_FrHslPrintf0 (0x4890, HSL_DBG_SN_ALL_DEBUG, "HSL SelfTest printf 0 arg:");
146 }
147 for(i=0; i < pCommand->mCntPrintf1p; i++)
148 {
149 M_FrHslPrintf1 (0x37D05, HSL_DBG_SN_ALL_DEBUG, "HSL SelfTest printf 1 arg: %X", 0xFF);
150 }
151 for(i=0; i < pCommand->mCntArray16; i++)
152 {
153 MS_U16 sndArray[pCommand->mParamArray16Size];
154 memset(sndArray, 0x16, sizeof(sndArray));
155 M_FrHslArray16 (0xAD99, HSL_DBG_SN_ALL_DEBUG, "HSL SelfTest array16: %X", pCommand->mParamArray16Size, sndArray);
156 }
157 for(i=0; i< pCommand->mCntArray32; i++)
158 {
159 MS_U32 sndArray[pCommand->mParamArray32Size];
160 memset(sndArray, 0x32, sizeof(sndArray));
161 M_FrHslArray32 (0xAB54, HSL_DBG_SN_ALL_DEBUG, "HSL SelfTest array32: %X", pCommand->mParamArray32Size, sndArray, 0);
162 }
163 for(i=0; i < pCommand->mCntTypedef; i++)
164 {
165 ST_TEST_STRUCT testStruct;
166 testStruct.a = 0x1234;
167 testStruct.b = 0x5678;
168 testStruct.c = 0xABCD;
169 M_FrHslTypedef (0xA4A4, HSL_DBG_SN_ALL_DEBUG, "HSL SelfTest typedef: %d", ST_TEST_STRUCT, &testStruct );
170 }
171 usleep(pCommand->mThreadDelay*1000); // convert the parameter from usec into msec
172 gettimeofday(&timeNow, 0);
173 }
174 return 0;
175 }
176
177 const MS_U8 syncBuf[] = {HSL_RAWLOB_SYNC_MARKER};
178
GetSystemTime(void)179 MS_U32 GetSystemTime(void)
180 {
181 return MDrv_TIMER_GetCounter (E_TIMER_1);
182 }
183
184 // PENDING WRITE LINKED LIST OPERATIONS
185
186 /* Should only be called from the listAppendValue */
listFindNextFreeNode(stHslController * _hsl)187 stListNode* listFindNextFreeNode( stHslController *_hsl )
188 {
189 stListNode *retVal = 0;
190 if( _hsl != 0)
191 {
192 int i = 0;
193 if( _hsl->pendingWriteHead == 0 )
194 {
195 retVal = &(_hsl->pendingWriteList[0]);
196 }
197 else
198 {
199 for( i=0; (i<PENDING_WRITE_LIST_LEN) && (_hsl->pendingWriteList[i].u32bufferIndex || _hsl->pendingWriteList[i].u32timestamp); i++ ){};
200 retVal = &(_hsl->pendingWriteList[i]);
201 }
202 }
203 return retVal;
204 }
205
listAppendValue(stHslController * _hsl,MS_U32 newValue)206 stListNode* listAppendValue(stHslController *_hsl, MS_U32 newValue)
207 {
208 stListNode *currentNode = 0;
209 stListNode *lastNode = 0;
210 if(_hsl!=0)
211 {
212 pthread_mutex_lock( &(_hsl->pendingWriteMutex) );
213 //assert(_hsl->pendingWriteLength < PENDING_WRITE_LIST_LEN );
214 currentNode = listFindNextFreeNode(_hsl);
215 assert( currentNode != 0 );
216 currentNode->u32bufferIndex = newValue;
217 if(_hsl->pendingWriteHead == 0 )
218 {
219 _hsl->pendingWriteHead = currentNode;
220 currentNode->prev = 0;
221 }
222 else
223 {
224 // find the tail
225 lastNode = _hsl->pendingWriteHead;
226 while(lastNode->next)
227 {
228 lastNode = lastNode->next;
229 }
230 lastNode->next = currentNode;
231 currentNode->prev = lastNode;
232 }
233 currentNode->next = 0;
234 _hsl->pendingWriteLength++;
235 pthread_mutex_unlock( &(_hsl->pendingWriteMutex) );
236 }
237 return currentNode;
238 }
239
listRemoveNode(stHslController * _hsl,stListNode * node)240 void listRemoveNode(stHslController *_hsl, stListNode *node)
241 {
242 if(_hsl!=0)
243 {
244 pthread_mutex_lock( &(_hsl->pendingWriteMutex) );
245 //assert( _hsl->pendingWriteHead != 0 );
246
247 if(node == _hsl->pendingWriteHead)
248 {
249 _hsl->pendingWriteHead = node->next;
250 }
251
252 if(node->prev)
253 {
254 node->prev->next = node->next;
255 }
256 if(node->next)
257 {
258 node->next->prev = node->prev;
259 }
260 node->u32bufferIndex = 0;
261 node->u32timestamp = 0;
262 node->prev = 0;
263 node->next = 0;
264 _hsl->pendingWriteLength--;
265 pthread_mutex_unlock( &(_hsl->pendingWriteMutex) );
266 }
267 }
268
listGetFirstValue(stHslController * _hsl)269 MS_U32 listGetFirstValue( stHslController *_hsl )
270 {
271 MS_U32 retVal = 0;
272 if(_hsl!=0)
273 {
274 retVal = 0;
275 pthread_mutex_lock( &(_hsl->pendingWriteMutex) );
276 if( _hsl->pendingWriteHead == 0 )
277 {
278 retVal = 0;
279 }
280 else
281 {
282 retVal = _hsl->pendingWriteHead->u32bufferIndex;
283 }
284 pthread_mutex_unlock( &(_hsl->pendingWriteMutex) );
285 }
286 return retVal;
287 }
288
listIsEmpty(stHslController * _hsl)289 MS_BOOL listIsEmpty(stHslController *_hsl)
290 {
291 MS_BOOL retVal = true;
292 if(_hsl!=0)
293 {
294 pthread_mutex_lock( &(_hsl->pendingWriteMutex) );
295 retVal = (_hsl->pendingWriteHead == 0);
296 pthread_mutex_unlock( &(_hsl->pendingWriteMutex) );
297 }
298 return retVal;
299 }
300
301 ////////////////////////////////////////////////////////////////////////////////
302 // GENERAL MESSAGE PROCESSING FUNCTIONS
303 ////////////////////////////////////////////////////////////////////////////////
304
305 /*******************************************************************************
306 Function:
307 sendBytesToStream
308 Description:
309 Output bytes of data from a message in the buffer, only the bytes less than outputLen will be output
310 INPUT:
311 MS_U8*: output buffer
312 MS_U32: total bytes need to output
313 OUTPUT:
314 Data to a device - currently UART.
315 RETURNS:
316 MS_BOOL: the whole bytes in message was written out or not
317 *******************************************************************************/
bufferSendBytes(p_HslController _hsl,const MS_U8 * const pu8MessageBuffer,const MS_U32 u32totalBytes)318 MS_BOOL bufferSendBytes(p_HslController _hsl, const MS_U8* const pu8MessageBuffer, const MS_U32 u32totalBytes)
319 {
320 PUTCS(pu8MessageBuffer, u32totalBytes, FR_HSL_FILE_DESCRIPTOR, _hsl);
321 return FALSE;
322 }
323
324 /*******************************************************************************
325 Function:
326 bufferWriteThread
327 Description:
328 output Data to UART
329 *******************************************************************************/
bufferWriteThread(void * data)330 void* bufferWriteThread(void* data)
331 {
332 //TODO!: Write a new simplified ring buffer output procedure
333 struct timeval now;
334 struct timespec timeout;
335 MS_U32 txSize;
336 MS_U32 txPos;
337 MS_U8 txBuffer[TX_BUFFER_SIZE];
338 MS_U32 txBufPos;
339 MS_U32 dumpReadPos;
340 MS_U32 dumpInfoPos=0;
341 MS_U8* dumpInfoBuf=NULL;
342 MS_BOOL resetBufEnd = FALSE;
343
344 p_HslController _hsl = (p_HslController)data;
345
346 pthread_mutex_lock(&(_hsl->outputCondMutex));
347 while( !(_hsl->thread_finalize) )
348 {
349
350 gettimeofday(&now, 0);
351 timeout.tv_sec = now.tv_sec + 1;
352 timeout.tv_nsec = now.tv_usec;
353
354 /* Checks to the pthread_cond_timedwait return immediately with an exception of the ETIMEDOUT
355 * Any other check will lose the blocking behaviour and will result in a tight loop executing
356 * the default case (add timerwraps) with high frequency and consuming lots of system's resources.
357 * Please see 'man pthread_cond_timedwait' for details.
358 */
359
360 if( (_hsl->pSystemState->bufFlags != BUFFER_FLAG_NONE) ||
361 (ETIMEDOUT != pthread_cond_timedwait( &(_hsl->outputCond), &(_hsl->outputCondMutex), &timeout )) )
362 {
363 if( _hsl->pSystemState->bufFlags & BUFFER_FLAG_EMERGENCY_DUMP )
364 {
365 pthread_cond_wait(&(_hsl->outputCond), &(_hsl->outputCondMutex));
366 }
367
368 if( _hsl->pSystemState->bufFlags & BUFFER_FLAG_TX )
369 {
370 /* Additional info about the usage of bufReadPos below: what coverity misses is that:
371 - Every write access to this variable is protected by holding both of the: bufferMutex and outputCondMutex
372 - Every read is protected by holding at least one of them.
373 This provides enough locking to ensure that the value is always consistent between threads yet provides enough
374 freedom for multiple threads to operate concurrently if they only require reading. */
375 txPos = _hsl->pSystemState->bufReadPos;
376 if(_hsl->pSystemState->dumpFlag != BUFFER_FLAG_NONE)
377 {
378 switch(_hsl->pSystemState->dumpFlag)
379 {
380 case BUFFER_FLAG_DUMP:
381 dumpInfoPos = DUMP_LP_LEN;
382 dumpInfoBuf = s_DumpBufferLP;
383 break;
384 case BUFFER_FLAG_EMERGENCY_DUMP:
385 dumpInfoPos = DUMP_LP_LEN;
386 dumpInfoBuf = s_CriticalDumpBufferLP;
387 break;
388 default:
389 dumpInfoPos = 0;
390 dumpInfoBuf = NULL;
391 break;
392 }
393 }
394 while( _hsl->pSystemState->bufBytesToSend > 0 )
395 {
396 txBufPos = 0;
397 while((txBufPos < TX_BUFFER_SIZE-1) && (_hsl->pSystemState->bufBytesToSend > 0))
398 {
399 // is it time to send a sync marker?
400 if( _hsl->pSystemState->syncMarker == 0 )
401 {
402 txBuffer[txBufPos] = HSL_RAWLOB_SYNC_MARKER;
403 txBufPos++;
404 --(_hsl->pSystemState->bufBytesToSend);
405 _hsl->pSystemState->syncMarker = HSL_RAWLOB_SYNC_MARKER_INTERVAL;
406 }
407
408 // does the remaining data fill the space to the nearest sync marker?
409 if( _hsl->pSystemState->bufBytesToSend >= _hsl->pSystemState->syncMarker )
410 {
411 txSize = _hsl->pSystemState->syncMarker;
412 }
413 else
414 {
415 txSize = _hsl->pSystemState->bufBytesToSend;
416 }
417
418
419 if(txSize > 0)
420 {
421 // need to inject a data dump information logpoint?
422 if(dumpInfoPos > 0)
423 {
424 if(txSize > dumpInfoPos)
425 {
426 txSize = dumpInfoPos;
427 }
428
429 dumpReadPos = DUMP_LP_LEN-dumpInfoPos;
430
431 if( dumpReadPos + txSize <= DUMP_LP_LEN )
432 {
433 memcpy(txBuffer+txBufPos, dumpInfoBuf+dumpReadPos, txSize);
434 }
435
436 dumpInfoPos -= txSize;
437
438 }
439 else
440 {
441 if( (txPos + txSize) >= _hsl->pSystemState->bufUsedEnd )
442 {
443 txSize = _hsl->pSystemState->bufUsedEnd - txPos;
444 }
445
446 if( txBufPos + txSize >= TX_BUFFER_SIZE )
447 {
448 txSize = TX_BUFFER_SIZE - txBufPos;
449 }
450
451 // data TX
452 memcpy(txBuffer+txBufPos, (MS_U8*)txPos, txSize);
453
454 txPos += txSize;
455 /* IMPORTANT !!!
456 * The txPos (and effectively the bufReadPos) can only wrap around if the bufReadLimit has
457 * wrapped around previously. This is to avoid a corner case when the read limit sits right at the end
458 * of the buffer and after catching up with it, the read pos is updated to the beginning of the buffer
459 * resulting in the complete OLD buffer contents to be sent again.
460 */
461 if( (txPos >= _hsl->pSystemState->bufUsedEnd) && (_hsl->pSystemState->bufReadLimit < _hsl->pSystemState->bufReadPos) )
462 {
463 // mark the buffer's end for restoration once we've read past the previous virtual one
464 resetBufEnd = TRUE;
465 txPos = _hsl->pSystemState->bufStart;
466 }
467 }
468 // update tx markers
469 _hsl->pSystemState->syncMarker = (_hsl->pSystemState->syncMarker - txSize);
470 _hsl->pSystemState->bufBytesToSend -= txSize;
471 txBufPos += txSize;
472 }
473 }
474 bufferSendBytes(_hsl, txBuffer, txBufPos);
475 }
476
477 // data successfully sent, update read position.
478 pthread_mutex_lock(&(_hsl->bufferMutex));
479 _hsl->pSystemState->bufReadPos = txPos;
480 _hsl->pSystemState->bufFlags &= ~BUFFER_FLAG_TX;
481 _hsl->pSystemState->dumpFlag = BUFFER_FLAG_NONE;
482 if( resetBufEnd )
483 {
484 _hsl->pSystemState->bufUsedEnd = _hsl->pSystemState->bufEnd;
485 resetBufEnd = FALSE;
486 }
487 pthread_mutex_unlock(&(_hsl->bufferMutex));
488 }
489 if( _hsl->pSystemState->bufFlags & BUFFER_FLAG_DUMP )
490 {
491 // dump data
492 pthread_mutex_lock(&(_hsl->bufferMutex));
493 _hsl->pSystemState->dumpFlag = BUFFER_FLAG_DUMP;
494 bufferDumpOldestDataSegment(_hsl);
495 _hsl->pSystemState->bufFlags &= ~BUFFER_FLAG_DUMP;
496 pthread_mutex_unlock(&(_hsl->bufferMutex));
497 }
498 }
499 else
500 {
501 // no data to be allocated but it will add some timer wraps
502 pthread_mutex_unlock(&(_hsl->outputCondMutex));
503 if( bufferAllocateWrite(_hsl, 0,0) )
504 {
505 // coverity thinks that the return value should be checked....
506 continue;
507 }
508 pthread_mutex_lock(&(_hsl->outputCondMutex));
509 }
510 }
511 pthread_mutex_unlock(&(_hsl->outputCondMutex));
512 return NULL;
513 }
514
515
516 ////////////////////////////////////////////////////////////////////////////////
517 // THREAD FUNCTIONS
518 ////////////////////////////////////////////////////////////////////////////////
519
520 /*******************************************************************************
521 Function:
522 Description:
523 INPUT:
524 OUTPUT:
525 *******************************************************************************/
deleteThread(hslThread aThread)526 MS_BOOL deleteThread(hslThread aThread)
527 {
528 MS_U32 rc=false;
529
530 if (0 == pthread_detach(aThread.threadId))
531 {
532 rc = true;
533 }
534
535 return rc;
536 }
537
538 /*******************************************************************************
539 Function:
540 Description:
541 INPUT:
542 OUTPUT:
543 *******************************************************************************/
initThread(hslThread * aThread)544 MS_BOOL initThread(hslThread* aThread)
545 {
546 MS_BOOL rc = false;
547
548 if (0 == pthread_create( &(aThread->threadId), NULL, aThread->funcPtr, aThread->funcParam))
549 {
550 rc = true;
551 }
552
553 return rc;
554 }
555
556 ////////////////////////////////////////////////////////////////////////////////
557 // MUTEX FUNCTIONS
558 ////////////////////////////////////////////////////////////////////////////////
559
560 /*******************************************************************************
561 Function:
562 initMutex
563 Description:
564 INPUT:
565 OUTPUT:
566 *******************************************************************************/
initMutex(pthread_mutex_t * pMutex)567 MS_BOOL initMutex(pthread_mutex_t* pMutex)
568 {
569 MS_BOOL rc = false;
570
571 if (0 == pthread_mutex_init(pMutex, NULL))
572 {
573 rc = true;
574 }
575
576 return rc;
577 }
578
579 /*******************************************************************************
580 Function:
581 Description:
582 INPUT:
583 OUTPUT:
584 *******************************************************************************/
deleteMutex(pthread_mutex_t * pMutex)585 MS_BOOL deleteMutex(pthread_mutex_t* pMutex)
586 {
587 MS_BOOL rc = false;
588
589 if (0 == pthread_mutex_destroy(pMutex))
590 {
591 rc = true;
592 }
593
594 return rc;
595 }
596
597 ////////////////////////////////////////////////////////////////////////////////
598 // CONDITION FUNCTIONS
599 ////////////////////////////////////////////////////////////////////////////////
600
601 /*******************************************************************************
602 Function:
603 initCondition
604 Description:
605 Initilises a condition variable.
606 INPUT:
607 pCond - pointer to a condition varaible.
608 OUTPUT:
609 None.
610 RETURNS:
611 rc - indicates success or failure of initialisation
612 *******************************************************************************/
initCondition(pthread_cond_t * pCond)613 MS_BOOL initCondition(pthread_cond_t* pCond)
614 {
615 MS_BOOL rc = false;
616
617 if (0 == pthread_cond_init(pCond, NULL))
618 {
619 rc = true;
620 }
621
622 return rc;
623 }
624
625 /*******************************************************************************
626 Function:
627 deleteCondition
628 Description:
629 Deletes a condition variable.
630 INPUT:
631 pCond - pointer to a condition varaible.
632 OUTPUT:
633 None.
634 RETURNS:
635 rc - indicates success or failure of initialisation
636 *******************************************************************************/
deleteCondition(pthread_cond_t * pCond)637 MS_BOOL deleteCondition(pthread_cond_t* pCond)
638 {
639 MS_BOOL rc = false;
640
641 if (0 == pthread_cond_destroy(pCond))
642 {
643 rc = true;
644 }
645
646 return rc;
647 }
648
649 ////////////////////////////////////////////////////////////////////////////////
650 // INIT FUNCTIONS
651 ////////////////////////////////////////////////////////////////////////////////
652
653 /*******************************************************************************
654 Function:
655 initBuffer
656 Description:
657 Initialises the data structure for the ring buffer and partitions the
658 memory to contain the system state and the ring buffer data.
659 INPUT:
660 size - size of the memory available.
661 physAddr - starting address of the memory in RAM (needs to be remapped for
662 this process).
663 OUTPUT:
664 None.
665 *******************************************************************************/
initBufferMemory(stHslController * const _hsl,const MS_U32 size,const MS_PHYADDR physAddr)666 MS_BOOL initBufferMemory(stHslController* const _hsl, const MS_U32 size, const MS_PHYADDR physAddr)
667 {
668 MS_U32 virtualAddress;
669 int i;
670 if ( size != 0 )
671 {
672 pthread_mutex_lock(&(_hsl->outputCondMutex));
673 pthread_mutex_lock(&(_hsl->bufferMutex));
674
675 if(physAddr != 0)
676 {
677 // save intial params. and buffer ptrs and sizes to system state structure
678 // required to store system state in ringbuffer so need to allocate 2K.
679 // from buffer of 512K.
680
681 // convert physical address to one mapped into process memory space.
682 virtualAddress = MsOS_MPool_PA2VA(physAddr);
683 }
684 else
685 {
686 virtualAddress = (MS_U32)malloc(size);
687 assert(virtualAddress!=0);
688 }
689
690 // initialise memory
691 memset( (MS_U8*)virtualAddress, 0, size);
692
693 // locate system state structure at beginning of allocated memory
694 _hsl->pSystemState = (stSystemState*)(virtualAddress);
695
696 if( physAddr != 0 )
697 {
698 _hsl->pSystemState->dynamicAlloc = 0;
699 }
700 else
701 {
702 _hsl->pSystemState->dynamicAlloc = 1;
703 }
704 // store pre-determined system state buffer size
705 _hsl->pSystemState->ssize = SYS_STATE_BUFSIZE;
706
707 // initialise rest of system state structure
708 _hsl->pSystemState->sbufStart = virtualAddress;
709 _hsl->pSystemState->sbufEnd = virtualAddress + SYS_STATE_BUFSIZE - 1;
710
711 // initialise the ringbuffer pointers
712 _hsl->pSystemState->bufSize = size - SYS_STATE_BUFSIZE;
713 _hsl->pSystemState->bufStart = virtualAddress + SYS_STATE_BUFSIZE;
714 _hsl->pSystemState->bufEnd = virtualAddress + size - 1;
715 _hsl->pSystemState->bufUsedEnd = _hsl->pSystemState->bufEnd;
716 _hsl->pSystemState->bufWritePos = _hsl->pSystemState->bufStart + 1; // leave one byte for the initial timer wrap
717 _hsl->pSystemState->bufReadPos = _hsl->pSystemState->bufStart;
718 _hsl->pSystemState->bufReadLimit = _hsl->pSystemState->bufWritePos;
719
720 _hsl->pSystemState->syncMarker = 0; // must be zero since the first byte should be sync byte
721
722 // the following values should remain constant throughout the execution
723 // calculated once on initialization
724 _hsl->pSystemState->bufMinFreeBytes = _hsl->pSystemState->bufSize * BUFFER_FREE_SPACE_PERCENTAGE / 100;
725 _hsl->pSystemState->bufSegmentSize = _hsl->pSystemState->bufSize / BUFFER_SEGMENTS_COUNT + 1;
726
727
728 // initialize bookmarks
729 _hsl->pSystemState->nextBookmark = 0;
730 _hsl->pSystemState->bufBookmarks[0].address = _hsl->pSystemState->bufStart;
731 _hsl->pSystemState->bufBookmarks[0].timerWrapDelta = 0;
732
733 // initialize flags
734 _hsl->pSystemState->bufFlags = BUFFER_FLAG_NONE;
735 _hsl->pSystemState->flushOnConnect = 0; // don't flush just after the reset
736 _hsl->pSystemState->dumpFlag = BUFFER_FLAG_NONE; // no dump at the beginning
737
738 // initialize timing
739 _hsl->pSystemState->hslLastTwTime = GetSystemTime();
740 *((MS_U8*)(_hsl->pSystemState->bufStart)) = HSL_RAWLOB_MSG_TYPE_TW_CHAN0;
741
742 _hsl->thread_finalize = false;
743
744 for(i=0; i<PENDING_WRITE_LIST_LEN; i++)
745 {
746 _hsl->pendingWriteList[i].u32bufferIndex = 0;
747 _hsl->pendingWriteList[i].u32timestamp = 0;
748 }
749 pthread_mutex_unlock(&(_hsl->bufferMutex));
750 pthread_mutex_unlock(&(_hsl->outputCondMutex));
751
752 return true;
753 }
754 else
755 {
756 return false;
757 }
758 }
759
deleteBufferMemory(stHslController * const _hsl)760 MS_BOOL deleteBufferMemory(stHslController* const _hsl)
761 {
762 if(_hsl->pSystemState->dynamicAlloc)
763 {
764 free((void*)(_hsl->pSystemState));
765 }
766 return true;
767 }
768 ////////////////////////////////////////////////////////////////////////////////
769 // EXTERNALLY EXPOSED FUNCTIONS
770 ////////////////////////////////////////////////////////////////////////////////
771
772 /*******************************************************************************
773 Function:
774 finalizeRingBuffer
775 Description:
776 flush output and kill any remaining threads
777 INPUT:
778 None.
779 OUTPUT:
780 None.
781 *******************************************************************************/
bufferFinalize(stHslController * const _hsl)782 MS_BOOL bufferFinalize(stHslController* const _hsl)
783 {
784 MS_BOOL rc = false;
785
786 // free(pDropInfo);
787
788 // tell output thread to stop output
789 _hsl->thread_finalize = true;
790
791 // delete condition variable
792 if(deleteThread(_hsl->logThreads[0]))
793 {
794 if(deleteCondition(&(_hsl->outputCond)))
795 {
796 if(deleteMutex(&(_hsl->outputCondMutex)))
797 {
798 if(deleteMutex(&(_hsl->inputMutex)))
799 {
800 if(deleteMutex(&(_hsl->bufferMutex)))
801 {
802 rc = deleteBufferMemory(_hsl);
803 }
804 }
805 }
806 }
807 }
808 return rc;
809 }
810
bufferCalculateFreeSpace(stHslController * const _hsl)811 MS_U32 bufferCalculateFreeSpace(stHslController* const _hsl)
812 {
813 MS_U32 retVal = 0;
814 if( _hsl->pSystemState->bufWritePos >= _hsl->pSystemState->bufReadPos )
815 {
816 retVal = _hsl->pSystemState->bufReadPos - _hsl->pSystemState->bufStart + _hsl->pSystemState->bufUsedEnd - _hsl->pSystemState->bufWritePos;
817 }
818 else
819 {
820 retVal = _hsl->pSystemState->bufReadPos - _hsl->pSystemState->bufWritePos;
821 }
822 return retVal;
823 }
824
825 /*******************************************************************************
826 Function:
827 bufferInitialize
828 Description:
829 Initialises the library - allocates the memory for the buffer, initialises
830 the mutex and the output thread.
831 INPUT:
832 physAddr - start addres in memory of buffer.
833 size - size in bytes of buffer.
834 OUTPUT:
835 None.
836 *******************************************************************************/
bufferInitialize(stHslController * const _hsl,const MS_PHYADDR physAddr,const MS_U32 size)837 MS_BOOL bufferInitialize(stHslController* const _hsl, const MS_PHYADDR physAddr, const MS_U32 size)
838 {
839 MS_BOOL rc = false;
840
841 if (initBufferMemory(_hsl, size, physAddr))
842 {
843 if (initMutex(&(_hsl->bufferMutex)))
844 {
845 if (initMutex(&(_hsl->inputMutex)))
846 {
847 if (initMutex(&(_hsl->outputCondMutex)))
848 {
849 if (initCondition(&(_hsl->outputCond)))
850 {
851 rc = initThread(&(_hsl->logThreads[0]));
852 }
853 }
854 }
855 }
856 }
857
858 return rc;
859 }
860
861 /*******************************************************************************
862 Function:
863 bufferDumpOldestDataSegment
864 Description:
865 Removes the oldest data from the buffer in order to prepare space
866 for new data
867 INPUT:
868 None.
869 OUTPUT:
870 None.
871 *******************************************************************************/
bufferDumpOldestDataSegment(stHslController * const _hsl)872 MS_BOOL bufferDumpOldestDataSegment(stHslController* const _hsl)
873 {
874 // copy the data between current read marker and the nearest bookmark
875 // to the dump buffer and add a warning logpoint at the end.
876 // after that move the read marker N bookmarks forward.
877
878 //find the nearest bookmark
879 int i = (_hsl->pSystemState->bufReadPos - _hsl->pSystemState->bufStart) / _hsl->pSystemState->bufSegmentSize;
880 if(i>0)
881 {
882 i--;
883 }
884 _hsl->pSystemState->flushOnConnect = 1;
885 while( _hsl->pSystemState->bufBookmarks[i].address <= _hsl->pSystemState->bufReadPos)
886 {
887 ++i;
888 }
889
890 // move the read pointer forward.
891 i = ( i + BUFFER_DUMP_SEGMENTS) % BUFFER_SEGMENTS_COUNT;
892
893 if( _hsl->pSystemState->bufBookmarks[i].address < _hsl->pSystemState->bufUsedEnd )
894 {
895 _hsl->pSystemState->bufReadPos = _hsl->pSystemState->bufBookmarks[i].address;
896 }
897 else
898 {
899 // need to wrap around the end of the buffer
900 _hsl->pSystemState->bufReadPos = _hsl->pSystemState->bufStart;
901 }
902
903 // Add a log point to inform the user about lost data
904 // The log point will be injected at current READ position
905 return TRUE;
906 }
907
908 /*******************************************************************************
909 Function:
910 getStartAddress
911 Description:
912 Populates a data structure showing next available writing positions.
913 INPUT:
914 dataSize - size in bytes of data to be written to buffer.
915 s_dataInfo - data structure containing pointers to write positions, size
916 of data to be written and flag indicating a wrap condition.
917 OUTPUT:
918 None.
919 *******************************************************************************/
bufferAllocateWrite(stHslController * const _hsl,const MS_U32 dataSize,stListNode ** const s_dataInfo)920 MS_BOOL bufferAllocateWrite(stHslController* const _hsl, const MS_U32 dataSize, stListNode** const s_dataInfo)
921 {
922 MS_BOOL rc = false;
923 MS_U32 currentTime;
924 MS_U32 twDelta;
925 MS_U32 u32freeSpace;
926 MS_U32 u32tmpReadPtr;
927
928 pthread_mutex_lock(&(_hsl->inputMutex));
929 pthread_mutex_lock(&(_hsl->bufferMutex));
930 // pthread_mutex_lock(&dumpMutex);
931 // memory buffer exists ?
932 if ( !_hsl->thread_finalize )
933 {
934 // first things first - read the timestamp
935 currentTime = GetSystemTime();
936
937 // update the read limits first
938 if( _hsl->pSystemState->bufReadLimit != _hsl->pSystemState->bufWritePos )
939 {
940 u32tmpReadPtr = listGetFirstValue(_hsl);
941 if( u32tmpReadPtr == 0 ) // this means no writes are pending
942 {
943 _hsl->pSystemState->bufReadLimit = _hsl->pSystemState->bufWritePos;
944 }
945 else
946 {
947 _hsl->pSystemState->bufReadLimit = u32tmpReadPtr;
948 }
949 }
950
951 // calculate the number of missing timer wraps and save the timestamp
952 if( currentTime < _hsl->pSystemState->hslLastTwTime )
953 {
954 // the system clock has wrapped around
955 twDelta = 0x10000 - (_hsl->pSystemState->hslLastTwTime >> 16) + (currentTime >> 16);
956 }
957 else
958 {
959 twDelta = (currentTime >> 16) - (_hsl->pSystemState->hslLastTwTime >> 16);
960 }
961 /* WARNING: as it happens, sometimes the read from the hardware clock is incorrect
962 * which may result in large values of twDelta leading to the buffer being unable
963 * to accomodate so much data in one write.
964 * In a normal operation the value of twDelta should not exceed about 200.
965 * The following assert allows for a large slip in time readings but will still
966 * detect a major failure.
967 *
968 * It has been also observed that on some targets the hardware clock is not configured
969 * and started correctly. As a result all time readings are the same and as time
970 * measurement is an essential feature of hsl it will assert when a disfunctional clock
971 * is detected.
972 */
973 assert(_hsl->pSystemState->hslLastTwTime != currentTime);
974 assert(twDelta < ASSERT_RT_CLOCK_FAIL_TW);
975
976 _hsl->pSystemState->hslLastTwTime = currentTime;
977
978 if( _hsl->pSystemState->bufWritePos >= _hsl->pSystemState->bufReadPos )
979 {
980 // now see if we need to wrap around - when writing we always use the physical end of the buffer
981 if( (_hsl->pSystemState->bufEnd - _hsl->pSystemState->bufWritePos) < (twDelta + dataSize) )
982 {
983 _hsl->pSystemState->bufUsedEnd = _hsl->pSystemState->bufWritePos;
984 _hsl->pSystemState->bufWritePos = _hsl->pSystemState->bufStart;
985
986 // set the last bookmark: it should always be aligned with the end of readable data
987 _hsl->pSystemState->bufBookmarks[BUFFER_SEGMENTS_COUNT-1].address = _hsl->pSystemState->bufUsedEnd;
988 _hsl->pSystemState->nextBookmark = 0;
989 }
990 }
991
992 // if the free space drops below a threshold set a flag and notify the "garbage collector"
993 // an additional mutex required to enable releasing blocking output thread and wait here
994 u32freeSpace = bufferCalculateFreeSpace(_hsl);
995 while( u32freeSpace < twDelta + dataSize )
996 {
997 _hsl->pSystemState->bufFlags |= BUFFER_FLAG_EMERGENCY_DUMP;
998 pthread_mutex_unlock(&(_hsl->bufferMutex));
999 pthread_mutex_lock(&(_hsl->outputCondMutex));
1000 pthread_mutex_lock(&(_hsl->bufferMutex));
1001 if(u32freeSpace < twDelta + dataSize) // must check again due to small probability of a complete buffer flush
1002 {
1003 _hsl->pSystemState->dumpFlag = BUFFER_FLAG_EMERGENCY_DUMP;
1004 bufferDumpOldestDataSegment(_hsl);
1005 }
1006 _hsl->pSystemState->bufFlags &= ~BUFFER_FLAG_EMERGENCY_DUMP;
1007 u32freeSpace = bufferCalculateFreeSpace(_hsl);
1008 pthread_cond_signal(&(_hsl->outputCond));
1009 pthread_mutex_unlock(&(_hsl->outputCondMutex));
1010 }
1011 if( u32freeSpace < _hsl->pSystemState->bufMinFreeBytes )
1012 {
1013 _hsl->pSystemState->bufFlags |= BUFFER_FLAG_DUMP;
1014 pthread_cond_signal( &(_hsl->outputCond) );
1015 }
1016 // write the missing timer wraps
1017 memset( (MS_U8*)(_hsl->pSystemState->bufWritePos), HSL_RAWLOB_MSG_TYPE_TW_CHAN0, twDelta );
1018 _hsl->pSystemState->bufWritePos += twDelta;
1019
1020 // if we have a valid pointer to data info save the pending write data
1021 if( s_dataInfo )
1022 {
1023 // save the position of the pending write
1024 *s_dataInfo = listAppendValue(_hsl, _hsl->pSystemState->bufWritePos);
1025 (*s_dataInfo)->u32timestamp = currentTime;
1026 }
1027 else
1028 {
1029 _hsl->pSystemState->bufReadLimit = _hsl->pSystemState->bufWritePos + dataSize;
1030 }
1031 _hsl->pSystemState->bufWritePos += dataSize;
1032
1033 // did we pass a bookmark threshold? if yes save the position
1034 if( _hsl->pSystemState->bufWritePos >= _hsl->pSystemState->bufStart + (_hsl->pSystemState->bufSegmentSize * (_hsl->pSystemState->nextBookmark+1)) )
1035 {
1036 _hsl->pSystemState->bufBookmarks[_hsl->pSystemState->nextBookmark].address = _hsl->pSystemState->bufWritePos;
1037 ++(_hsl->pSystemState->nextBookmark);
1038 }
1039
1040 rc = true;
1041 }
1042
1043 // pthread_mutex_unlock(&dumpMutex);
1044 pthread_mutex_unlock(&(_hsl->bufferMutex));
1045 pthread_mutex_unlock(&(_hsl->inputMutex));
1046
1047 return rc;
1048 }
1049
bufferAcknowledgeWrite(stHslController * const _hsl,stListNode * const s_dataInfo)1050 void bufferAcknowledgeWrite( stHslController* const _hsl, stListNode* const s_dataInfo )
1051 {
1052 // no need to lock, the read limit will be updated on next allocate call
1053 listRemoveNode(_hsl, s_dataInfo);
1054 }
1055
1056 /*******************************************************************************
1057 Function:
1058 sendToCmdQue
1059 Description:
1060 send the command to ringbuffer's command queue.
1061 INPUT:
1062 pCmd - command queue header.
1063 OUTPUT:
1064 True/False.
1065 *******************************************************************************/
bufferProcessCommand(stHslController * const _hsl,CmdInfo * const pCmd)1066 MS_BOOL bufferProcessCommand(stHslController* const _hsl, CmdInfo* const pCmd)
1067 {
1068 switch( pCmd->u16Cmd)
1069 {
1070 case HSL_CMD_RB_TOTAL_SIZE:
1071 {
1072 pCmd->u32Len = _hsl->pSystemState->bufSize;
1073 pCmd->u32Len += _hsl->pSystemState->bufSize / HSL_RAWLOB_SYNC_MARKER_INTERVAL;
1074 /* NEED TO ADD 1KB TO THE REPORTED TOTAL BUFFER SIZE DUE TO AN ERROR IN HSLS
1075 * CAUSING A FALSE DETECTION ON A FIFO OVERFLOW
1076 */
1077 pCmd->u32Len += 1024;
1078 }
1079 break;
1080
1081 case HSL_CMD_RB_EXIST_DATA_SIZE:
1082 {
1083 pthread_mutex_lock( &(_hsl->bufferMutex) );
1084 if( _hsl->pSystemState->bufReadLimit >= _hsl->pSystemState->bufReadPos )
1085 {
1086 pCmd->u32Len = _hsl->pSystemState->bufReadLimit - _hsl->pSystemState->bufReadPos;
1087 }
1088 else
1089 {
1090 pCmd->u32Len = (_hsl->pSystemState->bufUsedEnd - _hsl->pSystemState->bufReadPos) + (_hsl->pSystemState->bufReadLimit - _hsl->pSystemState->bufStart);
1091 }
1092 if(_hsl->pSystemState->dumpFlag != BUFFER_FLAG_NONE)
1093 {
1094 pCmd->u32Len += DUMP_LP_LEN;
1095 }
1096 pCmd->u32Len += (HSL_RAWLOB_SYNC_MARKER_INTERVAL - _hsl->pSystemState->syncMarker + pCmd->u32Len) / HSL_RAWLOB_SYNC_MARKER_INTERVAL;
1097 //pCmd->u32Len += pSystemState->syncMarker / (pCmd->u32Len % HSL_RAWLOB_SYNC_MARKER_INTERVAL);
1098 pthread_mutex_unlock( &(_hsl->bufferMutex) );
1099 }
1100 break;
1101
1102 case HSL_CMD_SEND_DATA:
1103 {
1104 // mutex required to prevent inserting data in the middle of an HSL stream
1105 pthread_mutex_lock(&(_hsl->outputCondMutex));
1106
1107 PUTCS(pCmd->pu8Buf, pCmd->u32Len, FR_HSL_FILE_DESCRIPTOR, _hsl);
1108 FFLUSH(FR_HSL_FILE_DESCRIPTOR);
1109
1110 pthread_mutex_unlock(&(_hsl->outputCondMutex));
1111 }
1112 break;
1113
1114 case HSL_CMD_RESET:
1115 {
1116 pthread_mutex_lock(&(_hsl->outputCondMutex));
1117
1118 // Reset Sync Marker since the first byte needs to be a Sync Marker
1119 _hsl->pSystemState->bufBytesToSend = 0;
1120 _hsl->pSystemState->syncMarker = 0;
1121
1122 if(_hsl->pSystemState->flushOnConnect > 0)
1123 {
1124 pthread_mutex_lock(&(_hsl->bufferMutex)); // TODO: review if there are no possible deadlocks
1125 _hsl->pSystemState->bufUsedEnd = _hsl->pSystemState->bufEnd;
1126 _hsl->pSystemState->bufWritePos = _hsl->pSystemState->bufStart + 1; // leave one byte for the initial timer wrap
1127 _hsl->pSystemState->bufReadPos = _hsl->pSystemState->bufStart;
1128 _hsl->pSystemState->bufReadLimit = _hsl->pSystemState->bufWritePos;
1129
1130 _hsl->pSystemState->syncMarker = 0; // must be zero since the first byte should be sync byte
1131 // initialize bookmarks
1132
1133 _hsl->pSystemState->nextBookmark = 0;
1134 _hsl->pSystemState->bufBookmarks[0].address = _hsl->pSystemState->bufStart;
1135 _hsl->pSystemState->bufBookmarks[0].timerWrapDelta = 0;
1136
1137 // initialize flags
1138 _hsl->pSystemState->bufFlags = BUFFER_FLAG_NONE;
1139 _hsl->pSystemState->dumpFlag = BUFFER_FLAG_NONE;
1140
1141 // initialize timing
1142 _hsl->pSystemState->hslLastTwTime = GetSystemTime();
1143 *((MS_U8*)(_hsl->pSystemState->bufStart)) = HSL_RAWLOB_MSG_TYPE_TW_CHAN0;
1144 _hsl->pSystemState->flushOnConnect = 1;
1145
1146 pthread_mutex_unlock(&(_hsl->bufferMutex));
1147 }
1148 else
1149 {
1150 _hsl->pSystemState->flushOnConnect = 1;
1151 }
1152 pthread_mutex_unlock(&(_hsl->outputCondMutex));
1153
1154 // Dump base addresses of known loaded dynamic libraries
1155 int i = 0;
1156 for(i=0; i<gDynamicLibraryCount; i++)
1157 {
1158 gDynamicLibraryInfo[i].rec_no = i+1;
1159 gDynamicLibraryInfo[i].rec_total = gDynamicLibraryCount;
1160 M_FrHslTypedef (0x80AB, HSL_DBG_SN_PROFILING, "Dynamic library base address: %d", ST_LIBRARY_SHORT_INFO, &gDynamicLibraryInfo[i]);
1161 }
1162 for(i=0; i<gThreadCount; i++)
1163 {
1164 M_FrHslTypedef (0x8DA6, HSL_DBG_SN_PROFILING, "Thread name: %d", ST_THREAD_INFO, &gThreadInfo[i]);
1165 }
1166 }
1167 break;
1168
1169 case HSL_CMD_GET_HSL_DATA:
1170 {
1171 pthread_mutex_lock(&(_hsl->outputCondMutex));
1172 pthread_mutex_lock(&(_hsl->bufferMutex));
1173 _hsl->pSystemState->bufFlags |= BUFFER_FLAG_TX;
1174 _hsl->pSystemState->bufBytesToSend = pCmd->u32Len;
1175 pthread_cond_signal(&(_hsl->outputCond));
1176 pthread_mutex_unlock(&(_hsl->bufferMutex));
1177 pthread_mutex_unlock(&(_hsl->outputCondMutex));
1178 }
1179 break;
1180
1181 default:
1182 {
1183 return FALSE;
1184 }
1185 break;
1186 }
1187 return TRUE;
1188 }
1189
1190 #endif
1191
1192