void Example1Rx::processBlock(SuperBlock& superBlock) { if (superBlock.header.frameIndex != m_frameHead) { if (m_dataCount != m_params.OriginalCount) { std::cerr << "Example1Rx::processBlock: incomplete frame" << std::endl; } m_frameCount++; m_blockCount = 0; m_metaReceived = false; m_dataCount = 0; m_recoveryCount = 0; m_frameHead = superBlock.header.frameIndex; } if (m_blockCount < m_params.OriginalCount) // not enough to decode => store data { int blockIndex = superBlock.header.blockIndex; if (blockIndex < m_params.OriginalCount) // data { m_data[blockIndex] = superBlock.protectedBlock; m_descriptorBlocks[m_blockCount].Block = (void *) &m_data[blockIndex]; m_descriptorBlocks[m_blockCount].Index = blockIndex; m_dataCount++; if (blockIndex == 0) { MetaDataFEC *metaData = (MetaDataFEC *) &m_data[blockIndex]; if (!(*metaData == m_currentMeta)) { m_currentMeta = *metaData; } m_metaReceived = true; } // if (blockIndex == 1) // { // std::srand(superBlock.header.frameIndex); // std::cerr << "Example1Rx::processBlock: " << superBlock.header.frameIndex << ": "; // // for (int k = 0; k < 2; k++) // { // uint16_t refI = std::rand(); // uint16_t refQ = std::rand(); // // std::cerr << "[" << k << "] " << m_data[blockIndex].samples[k].i // << "/" << m_data[blockIndex].samples[k].q // << " " << refI // << "/" << refQ // << " "; // } // // std::cerr << std::endl; // } } else // recovery data { m_recovery[m_recoveryCount] = superBlock.protectedBlock; m_descriptorBlocks[m_blockCount].Block = (void *) &m_recovery[m_recoveryCount]; m_descriptorBlocks[m_blockCount].Index = blockIndex; m_recoveryCount++; } } m_blockCount++; if (m_blockCount == m_params.OriginalCount) // enough data is received { if (m_cm256_OK && (m_recoveryCount > 0)) // FEC necessary { if (cm256_decode(m_params, m_descriptorBlocks)) // failure to decode { std::cerr << "Example1Rx::processBlock: CM256 decode error" << std::endl; } else // success to decode { std::cerr << "Example1Rx::processBlock: CM256 decode success: "; int recoveryStart = m_dataCount; for (int ir = 0; ir < m_recoveryCount; ir++) { int blockIndex = m_descriptorBlocks[recoveryStart + ir].Index; std::cerr << blockIndex << " "; m_data[blockIndex] = *((ProtectedBlock *) m_descriptorBlocks[recoveryStart + ir].Block); m_dataCount++; } std::cerr << std::endl; } } if (m_dataCount == m_params.OriginalCount) { checkData(); } } }
bool ExampleFileUsage() { if (cm256_init()) { return false; } cm256_encoder_params params; // Number of bytes per file block params.BlockBytes = 1296; // Number of blocks params.OriginalCount = 100; // Number of additional recovery blocks generated by encoder params.RecoveryCount = 30; // Size of the original file static const int OriginalFileBytes = params.OriginalCount * params.BlockBytes; // Allocate and fill the original file data uint8_t* originalFileData = new uint8_t[OriginalFileBytes]; for (int i = 0; i < OriginalFileBytes; ++i) { originalFileData[i] = (uint8_t)i; } // Pointers to data cm256_block blocks[256]; for (int i = 0; i < params.OriginalCount; ++i) { blocks[i].Block = originalFileData + i * params.BlockBytes; } // Recovery data uint8_t* recoveryBlocks = new uint8_t[params.RecoveryCount * params.BlockBytes]; // Generate recovery data if (cm256_encode(params, blocks, recoveryBlocks)) { delete[] originalFileData; delete[] recoveryBlocks; return false; } // Initialize the indices for (int i = 0; i < params.OriginalCount; ++i) { blocks[i].Index = cm256_get_original_block_index(params, i); } //// Simulate loss of data, substituting a recovery block in its place //// for (int i = 0; i < params.RecoveryCount && i < params.OriginalCount; ++i) { blocks[i].Block = recoveryBlocks + params.BlockBytes * i; // First recovery block blocks[i].Index = cm256_get_recovery_block_index(params, i); // First recovery block index } //// Simulate loss of data, substituting a recovery block in its place //// if (cm256_decode(params, blocks)) { delete[] originalFileData; delete[] recoveryBlocks; return false; } for (int i = 0; i < params.RecoveryCount && i < params.OriginalCount; ++i) { uint8_t* block = (uint8_t*)blocks[i].Block; int index = blocks[i].Index; for (int j = 0; j < params.BlockBytes; ++j) { const uint8_t expected = (uint8_t)(j + index * params.BlockBytes); if (block[j] != expected) { delete[] originalFileData; delete[] recoveryBlocks; return false; } } } delete[] originalFileData; delete[] recoveryBlocks; return true; }
bool example2() { static const int payloadSize = 256; // represents 4 subframes of 64 bytes #pragma pack(push, 1) struct ProtectedBlock { uint8_t blockIndex; uint8_t data[payloadSize]; }; struct SuperBlock { uint8_t frameIndex; uint8_t blockIndex; ProtectedBlock protectedBlock; }; #pragma pack(pop) if (cm256_init()) { return false; } cm256_encoder_params params; // Number of bytes per file block params.BlockBytes = sizeof(ProtectedBlock); // Number of blocks params.OriginalCount = 128; // Superframe = set of protected frames // Number of additional recovery blocks generated by encoder params.RecoveryCount = 32; SuperBlock* txBuffer = new SuperBlock[params.OriginalCount+params.RecoveryCount]; ProtectedBlock* txRecovery = new ProtectedBlock[params.RecoveryCount]; cm256_block txDescriptorBlocks[params.OriginalCount+params.RecoveryCount]; int frameCount = 0; // Fill original data for (int i = 0; i < params.OriginalCount+params.RecoveryCount; ++i) { txBuffer[i].frameIndex = frameCount; txBuffer[i].blockIndex = i; if (i < params.OriginalCount) { txBuffer[i].protectedBlock.blockIndex = i; for (int j = 0; j < payloadSize; ++j) { txBuffer[i].protectedBlock.data[j] = i; } txDescriptorBlocks[i].Block = (void *) &txBuffer[i].protectedBlock; txDescriptorBlocks[i].Index = txBuffer[i].blockIndex; } else { memset((void *) &txBuffer[i].protectedBlock, 0, sizeof(ProtectedBlock)); txDescriptorBlocks[i].Block = (void *) &txBuffer[i].protectedBlock; txDescriptorBlocks[i].Index = i; } } // Generate recovery data long long ts = getUSecs(); if (cm256_encode(params, txDescriptorBlocks, txRecovery)) { std::cerr << "example2: encode failed" << std::endl; delete[] txBuffer; delete[] txRecovery; return false; } long long usecs = getUSecs() - ts; std::cerr << "Encoded in " << usecs << " microseconds" << std::endl; // insert recovery data in sent data for (int i = 0; i < params.RecoveryCount; i++) { txBuffer[params.OriginalCount+i].protectedBlock = txRecovery[i]; } SuperBlock* rxBuffer = new SuperBlock[params.OriginalCount]; cm256_block rxDescriptorBlocks[params.OriginalCount]; int k = 0; for (int i = 0; i < params.OriginalCount+params.RecoveryCount; i++) { if (k < params.OriginalCount) { if (i % 5 != 4) { rxBuffer[k] = txBuffer[i]; rxDescriptorBlocks[k].Block = (void *) &rxBuffer[k].protectedBlock; rxDescriptorBlocks[k].Index = rxBuffer[k].blockIndex; k++; } } } ts = getUSecs(); if (cm256_decode(params, rxDescriptorBlocks)) { delete[] txBuffer; delete[] txRecovery; delete[] rxBuffer; return false; } usecs = getUSecs() - ts; for (int i = 0; i < params.OriginalCount; i++) { std::cerr << i << ":" << (unsigned int) rxBuffer[i].blockIndex << ":" << (unsigned int) rxBuffer[i].protectedBlock.blockIndex << ":" << (unsigned int) rxBuffer[i].protectedBlock.data[0] << std::endl; } std::cerr << "Decoded in " << usecs << " microseconds" << std::endl; delete[] txBuffer; delete[] txRecovery; delete[] rxBuffer; return true; }
/** * This is a more realistic example with separation of received data creation (mocking) and its processing */ bool example3() { #pragma pack(push, 1) struct Sample { uint16_t i; uint16_t q; }; struct Header { uint16_t frameIndex; uint8_t blockIndex; uint8_t filler; }; static const int samplesPerBlock = (512 - sizeof(Header)) / sizeof(Sample); struct ProtectedBlock { Sample samples[samplesPerBlock]; }; struct SuperBlock { Header header; ProtectedBlock protectedBlock; }; #pragma pack(pop) if (cm256_init()) { return false; } cm256_encoder_params params; // Number of bytes per file block params.BlockBytes = sizeof(ProtectedBlock); // Number of blocks params.OriginalCount = 128; // Superframe = set of protected frames // Number of additional recovery blocks generated by encoder params.RecoveryCount = 32; SuperBlock* txBuffer = new SuperBlock[params.OriginalCount+params.RecoveryCount]; ProtectedBlock* txRecovery = new ProtectedBlock[params.RecoveryCount]; cm256_block txDescriptorBlocks[params.OriginalCount+params.RecoveryCount]; int frameCount = 0; // Fill original data for (int i = 0; i < params.OriginalCount+params.RecoveryCount; ++i) { txBuffer[i].header.frameIndex = frameCount; txBuffer[i].header.blockIndex = i; if (i < params.OriginalCount) { txBuffer[i].protectedBlock.samples[0].i = i; // marker } else { memset((void *) &txBuffer[i].protectedBlock, 0, sizeof(ProtectedBlock)); } txDescriptorBlocks[i].Block = (void *) &txBuffer[i].protectedBlock; txDescriptorBlocks[i].Index = txBuffer[i].header.blockIndex; } // Generate recovery data long long ts = getUSecs(); if (cm256_encode(params, txDescriptorBlocks, txRecovery)) { std::cerr << "example2: encode failed" << std::endl; delete[] txBuffer; delete[] txRecovery; return false; } long long usecs = getUSecs() - ts; std::cerr << "Encoded in " << usecs << " microseconds" << std::endl; // insert recovery data in sent data for (int i = 0; i < params.RecoveryCount; i++) { txBuffer[params.OriginalCount+i].protectedBlock = txRecovery[i]; } SuperBlock* rxBuffer = new SuperBlock[params.OriginalCount + params.RecoveryCount]; // received blocks int k = 0; for (int i = 0; i < params.OriginalCount+params.RecoveryCount; i++) { if (i % 5 != 4) { rxBuffer[k] = txBuffer[i]; k++; } } Sample *samplesBuffer = new Sample[samplesPerBlock * params.OriginalCount]; ProtectedBlock* retrievedDataBuffer = (ProtectedBlock *) samplesBuffer; ProtectedBlock* recoveryBuffer = new ProtectedBlock[params.OriginalCount]; // recovery blocks with maximum size cm256_block rxDescriptorBlocks[params.OriginalCount]; int recoveryStartIndex; k = 0; for (int i = 0; i < params.OriginalCount; i++) { int blockIndex = rxBuffer[i].header.blockIndex; if (blockIndex < params.OriginalCount) // it's an original block { retrievedDataBuffer[blockIndex] = rxBuffer[i].protectedBlock; rxDescriptorBlocks[i].Block = (void *) &retrievedDataBuffer[blockIndex]; rxDescriptorBlocks[i].Index = blockIndex; } else // it's a recovery block { if (k == 0) { recoveryStartIndex = i; } recoveryBuffer[k] = rxBuffer[i].protectedBlock; rxDescriptorBlocks[i].Block = (void *) &recoveryBuffer[k]; rxDescriptorBlocks[i].Index = blockIndex; k++; } } ts = getUSecs(); if (cm256_decode(params, rxDescriptorBlocks)) { delete[] txBuffer; delete[] txRecovery; delete[] rxBuffer; delete[] samplesBuffer; delete[] recoveryBuffer; return false; } usecs = getUSecs() - ts; for (int i = 0; i < k; i++) // recover missing blocks { int blockIndex = rxDescriptorBlocks[recoveryStartIndex+i].Index; retrievedDataBuffer[blockIndex] = recoveryBuffer[i]; } for (int i = 0; i < params.OriginalCount; i++) { std::cerr << i << ":" << (unsigned int) rxDescriptorBlocks[i].Index << ":" << (unsigned int) retrievedDataBuffer[i].samples[0].i << std::endl; } std::cerr << "Decoded in " << usecs << " microseconds" << std::endl; delete[] txBuffer; delete[] txRecovery; delete[] rxBuffer; delete[] samplesBuffer; delete[] recoveryBuffer; return true; }
bool SDRdaemonFECBuffer::writeAndRead(uint8_t *array, std::size_t length, uint8_t *data, std::size_t& dataLength) { assert(length == udpSize); bool dataAvailable = false; dataLength = 0; SuperBlock *superBlock = (SuperBlock *) array; int frameIndex = superBlock->header.frameIndex; // std::cerr << "SDRdaemonFECBuffer::writeAndRead:" // << " frameIndex: " << frameIndex // << " decoderIndex: " << decoderIndex // << " blockIndex: " << blockIndex // << " i.q:"; // // for (int i = 0; i < 10; i++) // { // std::cerr << " " << (int) superBlock->protectedBlock.samples[i].i // << "." << (int) superBlock->protectedBlock.samples[i].q; // } // // std::cerr << std::endl; if ( m_frameHead != frameIndex) { getSlotData(data, dataLength); // copy slot data to output buffer dataAvailable = true; initDecodeSlot(); // re-initialize slot m_frameHead = frameIndex; } // decoderIndex should now be correctly set if (m_decoderSlot.m_blockCount < nbOriginalBlocks) // not enough blocks to decode -> store data { int blockCount = m_decoderSlot.m_blockCount; int recoveryCount = m_decoderSlot.m_recoveryCount; int blockIndex = superBlock->header.blockIndex; m_decoderSlot.m_cm256DescriptorBlocks[blockCount].Index = blockIndex; if (blockIndex == 0) // first block with meta { m_decoderSlot.m_metaRetrieved = true; } if (blockIndex < nbOriginalBlocks) // data block { m_decoderSlot.m_frame.m_blocks[blockIndex] = superBlock->protectedBlock; m_decoderSlot.m_cm256DescriptorBlocks[blockCount].Block = (void *) &m_decoderSlot.m_frame.m_blocks[blockIndex]; } else // redundancy block { m_decoderSlot.m_recoveryBlocks[recoveryCount] = superBlock->protectedBlock; m_decoderSlot.m_cm256DescriptorBlocks[blockCount].Block = (void *) &m_decoderSlot.m_recoveryBlocks[recoveryCount]; m_decoderSlot.m_recoveryCount++; } } m_decoderSlot.m_blockCount++; if (m_decoderSlot.m_blockCount == nbOriginalBlocks) // ready to decode { m_decoderSlot.m_decoded = true; if (m_cm256_OK && (m_decoderSlot.m_recoveryCount > 0)) // recovery data used and CM256 decoder available { m_paramsCM256.RecoveryCount = m_decoderSlot.m_recoveryCount; // // debug print // for (int ir = 0; ir < m_decoderSlots[decoderIndex].m_recoveryCount; ir++) // recovery blocks // { // int blockIndex = m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[nbRxOriginalBlocks+ir].Index; // ProtectedBlock *recoveryBlock = (ProtectedBlock *) m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[nbRxOriginalBlocks+ir].Block; // // std::cerr << "SDRdaemonFECBuffer::writeAndRead:" // << " recovery block #" << blockIndex // << " i.q: "; // // for (int i = 0; i < 10; i++) // { // std::cerr << " " << recoveryBlock->samples[i].i // << "." << recoveryBlock->samples[i].q; // } // // std::cerr << std::endl; // } // // end debug print if (cm256_decode(m_paramsCM256, m_decoderSlot.m_cm256DescriptorBlocks)) // failure to decode { std::cerr << "SDRdaemonFECBuffer::writeAndRead: CM256 decode error" << std::endl; } else // success to decode { int nbRxOriginalBlocks = nbOriginalBlocks - m_decoderSlot.m_recoveryCount; std::cerr << "SDRdaemonFECBuffer::writeAndRead: CM256 decode success:" << " nb recovery blocks: " << m_decoderSlot.m_recoveryCount << std::endl; for (int ir = 0; ir < m_decoderSlot.m_recoveryCount; ir++) // recover lost blocks { int recoveryIndex = nbOriginalBlocks - m_decoderSlot.m_recoveryCount + ir; int blockIndex = m_decoderSlot.m_cm256DescriptorBlocks[recoveryIndex].Index; ProtectedBlock *recoveredBlock = (ProtectedBlock *) m_decoderSlot.m_cm256DescriptorBlocks[recoveryIndex].Block; m_decoderSlot.m_frame.m_blocks[blockIndex] = *recoveredBlock; // if (blockIndex == 0) // { // m_decoderSlots[decoderIndex].m_metaRetrieved = true; // } // debug print std::cerr << "SDRdaemonFECBuffer::writeAndRead:" << " recovered block #" << blockIndex << " i.q: "; for (int i = 0; i < 10; i++) { std::cerr << " " << recoveredBlock->samples[i].i << "." << recoveredBlock->samples[i].q; } std::cerr << std::endl; // end debug print } // recover } // success to decode } // recovery data used if (m_decoderSlot.m_metaRetrieved) // meta data retrieved { MetaDataFEC *metaData = (MetaDataFEC *) &m_decoderSlot.m_frame.m_blocks[0]; if (!(*metaData == m_currentMeta)) { m_currentMeta = *metaData; printMeta(metaData); } } } // decode frame return dataAvailable; }