blob: c15dee4112860687d6c4dc50de26237423f9745b [file] [log] [blame]
/*******************************************************************************
* Trace Recorder Library for Tracealyzer v3.0.2
* Percepio AB, www.percepio.com
*
* trcPagedEventBuffer.c
*
* Implements a paged buffer that can be used by TCP/IP or custom transfer
* methods.
*
* Terms of Use
* This software (the "Tracealyzer Recorder Library") is the intellectual
* property of Percepio AB and may not be sold or in other ways commercially
* redistributed without explicit written permission by Percepio AB.
*
* Separate conditions applies for the SEGGER branded source code included.
*
* The recorder library is free for use together with Percepio products.
* You may distribute the recorder library in its original form, but public
* distribution of modified versions require approval by Percepio AB.
*
* Disclaimer
* The trace tool and recorder library is being delivered to you AS IS and
* Percepio AB makes no warranty as to its use or performance. Percepio AB does
* not and cannot warrant the performance or results you may obtain by using the
* software or documentation. Percepio AB make no warranties, express or
* implied, as to noninfringement of third party rights, merchantability, or
* fitness for any particular purpose. In no event will Percepio AB, its
* technology partners, or distributors be liable to you for any consequential,
* incidental or special damages, including any lost profits or lost savings,
* even if a representative of Percepio AB has been advised of the possibility
* of such damages, or for any claim by any third party. Some jurisdictions do
* not allow the exclusion or limitation of incidental, consequential or special
* damages, or the exclusion of implied warranties or limitations on how long an
* implied warranty may last, so the above limitations may not apply to you.
*
* Tabs are used for indent in this file (1 tab = 4 spaces)
*
* Copyright Percepio AB, 2015.
* www.percepio.com
******************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "trcConfig.h"
#include "trcPagedEventBuffer.h"
#include "trcPagedEventBufferConfig.h"
#include "trcKernelPort.h"
uint32_t DroppedEventCounter = 0; // Total number of dropped events (failed allocations)
uint32_t TotalBytesRemaining_LowWaterMark = TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
#if (USE_TRACEALYZER_RECORDER == 1)
#define PAGE_STATUS_FREE 0
#define PAGE_STATUS_WRITE 1
#define PAGE_STATUS_READ 2
uint32_t TotalBytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
typedef struct{
uint8_t Status;
uint16_t BytesRemaining;
char* WritePointer;
} PageType;
PageType PageInfo[TRC_PAGED_EVENT_BUFFER_PAGE_COUNT];
char* EventBuffer = NULL;
static void prvPageReadComplete(int pageIndex);
static int prvAllocateBufferPage(int prevPage);
static int prvAllocateBufferPage(int prevPage)
{
int index;
int count = 0;
index = (prevPage + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;
while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT))
{
index = (index + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;
}
if (PageInfo[index].Status == PAGE_STATUS_FREE)
{
return index;
}
return -1;
}
static void prvPageReadComplete(int pageIndex)
{
TRACE_ALLOC_CRITICAL_SECTION();
TRACE_ENTER_CRITICAL_SECTION();
PageInfo[pageIndex].BytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE];
PageInfo[pageIndex].Status = PAGE_STATUS_FREE;
TotalBytesRemaining += TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
TRACE_EXIT_CRITICAL_SECTION();
}
static int prvGetBufferPage(int32_t* bytesUsed)
{
static int8_t lastPage = -1;
int count = 0;
int8_t index = (lastPage + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;
while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT))
{
index = (index + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;
}
if (PageInfo[index].Status == PAGE_STATUS_READ)
{
*bytesUsed = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE - PageInfo[index].BytesRemaining;
lastPage = index;
return index;
}
*bytesUsed = 0;
return -1;
}
/*******************************************************************************
int32_t vPagedEventBufferTransfer(int32_t (*writeFunc)(void* data,
uint32_t size),
int32_t* nofBytes)
Transfers one block of trace data, if available for reading. Returns the number
of bytes transfered, or a negative error code. If data was transferred (return
value > 0), it can be good to call this function again until all data available
has been transfered.
This function is intended to be called by a periodic task with a suitable
delay (e.g. 10-100 ms).
Example:
TickType_t lastWakeTime = xTaskGetTickCount();
while(1)
{
do{
// Transfer all available data
status = vPagedEventBufferTransfer(MyWrite, ptrBytes);
}while(status > 0);
if (status < 0)
{
// A negative return value is an error code...
}
vTraceDelayUntil(lastWakeTime, 50); // 50 ms -> 20 times/sec
}
Return value: returnvalue of writeFunc (0 == OK)
Parameters:
- writeFunc
Function pointer (example: int32_t write(void* data, uint32_t size))
The function passed as writeFunc should write "size" bytes from "data" to the
socket/file/channel, and return a status code where 0 means OK,
and any other non-zero value means an error.
- int32_t* nofBytes
Pointer to an integer assigned the number of bytes that was transfered.
*******************************************************************************/
int32_t vPagedEventBufferTransfer(int32_t (*writeFunc)(void* data, uint32_t size, int32_t* ptrBytesWritten), int32_t* nofBytes)
{
static int firstTime = 1;
int8_t pageToTransfer = -1;
pageToTransfer = prvGetBufferPage(nofBytes);
if (firstTime)
{
firstTime = 0;
}
if (pageToTransfer > -1)
{
if (writeFunc(&EventBuffer[pageToTransfer * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE], *nofBytes, nofBytes) == 0)
{
prvPageReadComplete(pageToTransfer);
return 0;
}
else
{
return 1;
}
}
return 0;
}
/*******************************************************************************
void* vPagedEventBufferGetWritePointer(int sizeOfEvent)
Returns a pointer to an available location in the buffer able to store the
requested size.
Return value: The pointer.
Parameters:
- sizeOfEvent
The size of the event that is to be placed in the buffer.
*******************************************************************************/
void* vPagedEventBufferGetWritePointer(int sizeOfEvent)
{
void* ret;
static int currentWritePage = -1;
if (currentWritePage == -1)
{
currentWritePage = prvAllocateBufferPage(currentWritePage);
if (currentWritePage == -1)
{
DroppedEventCounter++;
return NULL;
}
}
if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0)
{
PageInfo[currentWritePage].Status = PAGE_STATUS_READ;
TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes
if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
currentWritePage = prvAllocateBufferPage(currentWritePage);
if (currentWritePage == -1)
{
DroppedEventCounter++;
return NULL;
}
}
ret = PageInfo[currentWritePage].WritePointer;
PageInfo[currentWritePage].WritePointer += sizeOfEvent;
PageInfo[currentWritePage].BytesRemaining -= sizeOfEvent;
TotalBytesRemaining -= sizeOfEvent;
if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
return ret;
}
/*******************************************************************************
void vPagedEventBufferInit(char* buffer)
Assigns the buffer to use and initializes the PageInfo structure.
Return value: void
Parameters:
- buffer
Pointer to the buffer location that is dynamically or statically allocated by
the caller.
*******************************************************************************/
void vPagedEventBufferInit(char* buffer)
{
TRACE_ALLOC_CRITICAL_SECTION();
int i;
EventBuffer = buffer;
TRACE_ENTER_CRITICAL_SECTION();
for (i = 0; i < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT; i++)
{
PageInfo[i].BytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
PageInfo[i].WritePointer = &EventBuffer[i * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE];
PageInfo[i].Status = PAGE_STATUS_FREE;
}
TRACE_EXIT_CRITICAL_SECTION();
}
#endif