2019-08-17 23:26:17 +02:00
|
|
|
#include "SessionChunk.h"
|
|
|
|
|
|
|
|
|
2019-08-22 21:33:36 +02:00
|
|
|
template<typename Measurement_T, typename Reader, typename Writer, uint32_t CHUNK_SIZE>
|
|
|
|
class MeasurementSession {
|
2019-08-17 23:26:17 +02:00
|
|
|
public:
|
|
|
|
typedef SessionChunk<Measurement_T, CHUNK_SIZE> Chunk_T;
|
|
|
|
|
2019-08-22 21:33:36 +02:00
|
|
|
MeasurementSession()
|
2019-08-17 23:26:17 +02:00
|
|
|
: currentChunk(&chunks[0]),
|
|
|
|
otherChunk(&chunks[1]) {}
|
|
|
|
|
|
|
|
void init(uint32_t epochStartTime) {
|
|
|
|
currentChunk = &chunks[0];
|
|
|
|
currentChunk->init(epochStartTime, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool addPoint(Measurement_T measurement) {
|
|
|
|
const bool successful = currentChunk->addPoint(measurement);
|
|
|
|
if (!successful) {
|
|
|
|
rotate();
|
|
|
|
const bool secondInsertSuccess = currentChunk->addPoint(measurement);
|
|
|
|
assert(secondInsertSuccess, "Session: insertion after rotation failed");
|
|
|
|
//TODO check that there is place for file - remove old files
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-08-18 19:41:19 +02:00
|
|
|
void finalize() {
|
|
|
|
if( otherChunkFilled() )
|
|
|
|
saveChunkToFile(otherChunk);
|
|
|
|
if( currentChunk->numMeasurements() > 0) {
|
|
|
|
saveChunkToFile(currentChunk);
|
|
|
|
}
|
|
|
|
currentChunk->init(0, 0);
|
|
|
|
otherChunk->init(0, 0);
|
|
|
|
}
|
|
|
|
|
2019-09-08 18:00:09 +02:00
|
|
|
template<typename Encoder_T>
|
|
|
|
void serialize(Encoder_T & encoder, uint32_t startIdx) const
|
2019-08-17 23:26:17 +02:00
|
|
|
{
|
|
|
|
const uint32_t lastIdx = currentChunk->getStartIndex() + currentChunk->numMeasurements();
|
|
|
|
if( lastIdx <= startIdx) {
|
2019-08-18 19:58:13 +02:00
|
|
|
encoder.template sendArray<Measurement_T>(nullptr, 0);
|
2019-08-17 23:26:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Chunk_T::sendHeader(encoder, currentChunk->getStartTime(), startIdx);
|
2019-08-18 19:58:13 +02:00
|
|
|
encoder.template sendArrayHeader<Measurement_T>(lastIdx - startIdx);
|
2019-08-17 23:26:17 +02:00
|
|
|
while(startIdx < lastIdx)
|
|
|
|
startIdx = serializeChunk(encoder, startIdx);
|
|
|
|
assert(startIdx == lastIdx, "Not all data was sent");
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void rotate() {
|
|
|
|
if( otherChunkFilled() )
|
|
|
|
saveChunkToFile(otherChunk);
|
|
|
|
swapChunks();
|
|
|
|
|
|
|
|
currentChunk->init(otherChunk->getStartTime(), otherChunk->getStartIndex() + CHUNK_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool otherChunkFilled() const {
|
|
|
|
return otherChunk->numMeasurements() > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void swapChunks() {
|
|
|
|
Chunk_T *tmp = currentChunk;
|
|
|
|
currentChunk = otherChunk;
|
|
|
|
otherChunk = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void saveChunkToFile(Chunk_T *chunk) const {
|
|
|
|
const uint32_t chunkNr = chunk->getStartIndex() / CHUNK_SIZE;
|
|
|
|
const auto fileName = chunkFileName(chunkNr, chunk->getStartTime());
|
|
|
|
Writer writer( fileName );
|
|
|
|
chunk->serialize(writer.encoder());
|
|
|
|
};
|
|
|
|
|
2019-09-08 18:00:09 +02:00
|
|
|
template< typename Encoder_T>
|
|
|
|
uint32_t serializeChunk(Encoder_T & encoder, uint32_t startIdx) const {
|
2019-08-17 23:26:17 +02:00
|
|
|
assert( startIdx < currentChunk->getStartIndex() + currentChunk->numMeasurements(),
|
|
|
|
"serializeChunk: invalid startIdx" );
|
|
|
|
|
|
|
|
if( startIdx >= currentChunk->getStartIndex() ) {
|
|
|
|
encoder.sendArrayPartialContents( currentChunk->getDataPointer(), currentChunk->numMeasurements() );
|
|
|
|
return currentChunk->getStartIndex() + currentChunk->numMeasurements();
|
|
|
|
} else if( startIdx >= otherChunk->getStartIndex() && otherChunkFilled() ) {
|
|
|
|
encoder.sendArrayPartialContents( otherChunk->getDataPointer(), otherChunk->numMeasurements() );
|
|
|
|
assert( otherChunk->numMeasurements(), CHUNK_SIZE );
|
|
|
|
return otherChunk->getStartIndex() + otherChunk->numMeasurements();
|
|
|
|
} else {
|
|
|
|
if( encoder.getSizeCountMode() ) {
|
2019-08-18 19:58:13 +02:00
|
|
|
encoder.template sendArrayPartialContents<Measurement_T>(nullptr, CHUNK_SIZE);
|
2019-08-17 23:26:17 +02:00
|
|
|
} else {
|
|
|
|
const uint32_t chunkNr = startIdx / CHUNK_SIZE;
|
2019-08-18 19:58:13 +02:00
|
|
|
const auto chunkFileNameStr = chunkFileName(chunkNr, currentChunk->getStartTime());
|
|
|
|
Reader reader(chunkFileNameStr);
|
2019-09-08 18:00:09 +02:00
|
|
|
reader.seek(Chunk_T::valueOffset());
|
2019-08-17 23:26:17 +02:00
|
|
|
|
|
|
|
const uint32_t PART_SIZE = 32;
|
2019-08-22 21:33:36 +02:00
|
|
|
#ifndef ARDUINO
|
|
|
|
static_assert((PART_SIZE < CHUNK_SIZE) && (CHUNK_SIZE % PART_SIZE == 0));
|
|
|
|
#endif
|
2019-08-17 23:26:17 +02:00
|
|
|
Measurement_T buffer[PART_SIZE];
|
|
|
|
for(uint32_t i = 0; i < CHUNK_SIZE; i += PART_SIZE)
|
|
|
|
{
|
|
|
|
reader.readBytes((char*) buffer, sizeof(Measurement_T) * PART_SIZE);
|
2019-08-18 19:58:13 +02:00
|
|
|
encoder.template sendArrayPartialContents<Measurement_T>(buffer, PART_SIZE);
|
2019-08-17 23:26:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return startIdx + CHUNK_SIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static String chunkFileName(uint32_t chunkNr, uint32_t startTime) {
|
|
|
|
return("/dat/" + toString(startTime) + "_" + toString(chunkNr));
|
|
|
|
}
|
|
|
|
|
|
|
|
Chunk_T chunks[2];
|
|
|
|
Chunk_T *currentChunk;
|
|
|
|
Chunk_T *otherChunk;
|
|
|
|
};
|