Simple data buffer splitter and re-assembler.
DataFragmenterAssembler.cpp
- Committer:
- ansond
- Date:
- 2015-02-12
- Revision:
- 0:12a931a6161c
File content as of revision 0:12a931a6161c:
/** * @file DataFragmenterAssembler.cpp * @brief data fragmenter and assembler (for BLE UARTService...) implementation * @author Doug Anson * @version 1.0 * @see * * Copyright (c) 2014 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "DataFragmenterAssembler.h" // we have to redefine DBG as its used differently here... #ifdef DBG #undef DBG #endif #define DBG printf // constructor DataFragmenterAssembler::DataFragmenterAssembler() { this->reset(); } // fragment a buffer int DataFragmenterAssembler::fragment(uint8_t *data,int data_length) { // reset this->reset(); // get our number of fragments this->m_num_fragments = this->calculateNumFragments(data,data_length); // DEBUG //DBG("fragment() num_fragments=%d data_length=%d\r\n",this->m_num_fragments,data_length); // make sure we have a positive number... if (this->m_num_fragments > 0) { // check for the simple case first if (this->m_num_fragments == 1) { // simple case... just 1 fragment memcpy(this->m_fragments[0],data,data_length); this->m_last_fragment_length = data_length; } else { // must iterate over the buffer and fragment... for(int i=0;i<this->m_num_fragments;++i) { int offset = i*DEF_FRAGMENT_LENGTH; if (i < (this->m_num_fragments-1)) { // interior... will always be fixed length memcpy(this->m_fragments[i],(data + offset),DEF_FRAGMENT_LENGTH); } else { // trailing... may be partial length... this->m_last_fragment_length = data_length - offset; memcpy(this->m_fragments[i],(data + offset),this->m_last_fragment_length); } } } } else { // unable to fragment... invalid parameters DBG("ERROR: invalid parameters in fragment()\r\n"); } // DEBUG //this->dump(); // return our number of fragments return this->m_num_fragments; } // calculate the number of fragments int DataFragmenterAssembler::calculateNumFragments(uint8_t *data,int data_length) { int num_fragments = 0; // param checking if (data != NULL && data_length > 0) { // check for simple case... if (data_length <= DEF_FRAGMENT_LENGTH) { num_fragments = 1; } else { num_fragments = 1; data_length -= DEF_FRAGMENT_LENGTH; while(data_length > 0) { ++num_fragments; data_length -= DEF_FRAGMENT_LENGTH; } } } else { // invalid parameters DBG("ERROR: invalid parameters in calculateNumFragments() data_length=%d\r\n",data_length); } return num_fragments; } // get the ith fragment uint8_t *DataFragmenterAssembler::get(int index) { if (index >= 0 && index < this->m_num_fragments) return this->m_fragments[index]; return NULL; } // reset the Fragmenter/Assembler void DataFragmenterAssembler::reset(void) { memset(this->m_fragments,0,sizeof(this->m_fragments)); this->m_num_fragments = 0; this->m_last_fragment_length = 0; } // add a fragment to assemble later int DataFragmenterAssembler::add(uint8_t *fragment,int fragment_length) { if (this->m_num_fragments < (MAX_FRAGMENTS-1)) { int length = fragment_length; if (length > DEF_FRAGMENT_LENGTH) { length = DEF_FRAGMENT_LENGTH; //DBG("WARNING: Truncating input fragment in add() fragment_length=%d\r\n",fragment_length); } memcpy(this->m_fragments[this->m_num_fragments],fragment,length); ++this->m_num_fragments; } else { // not enough memory to hold all the fragments DBG("ERROR: Maximum number of fragments permissible reached, Please increase MAX_FRAGMENTS...\r\n"); } return this->m_num_fragments; } // assemble all input fragments void DataFragmenterAssembler::assemble(uint8_t *buffer,int buffer_length,bool reset_after_assemble) { // calculate the final assembly length int length = this->calculateAssemblyLength(buffer_length); if (length > 0) { // initialize the return buffer memset(buffer,0,buffer_length); // check for the simple case.. 1 fragment if (this->m_num_fragments == 1) { // simple case detected... just copy over memset(buffer,0,buffer_length); memcpy(buffer,this->m_fragments[0],length); } else { // we have to loop and copy/append for(int i=0;i<this->m_num_fragments;++i) { int offset = (i*DEF_FRAGMENT_LENGTH); if (i < (this->m_num_fragments-1)) { // interior... will always be fixed length memcpy((buffer+offset),this->m_fragments[i],DEF_FRAGMENT_LENGTH); } else { // trailing... may be partial length... memcpy((buffer+offset),this->m_fragments[i],this->m_last_fragment_length); } } } // DEBUG //DBG("assemble(): buffer=[%s] length=%d\r\n",buffer,buffer_length); } else { // unable to assemble... DBG("ERROR: Unable to assemble. calculateAssemblyLength() failed (%d)\r\n",length); } } // calculate the assembled packet length int DataFragmenterAssembler::calculateAssemblyLength(int buffer_length) { int length = 0; for(int i=0;i<this->m_num_fragments;++i) { if (i < (this->m_num_fragments-1)) length += DEF_FRAGMENT_LENGTH; else length += this->m_last_fragment_length; } // sanity check if (length > buffer_length) { // input buffer is too small... DBG("ERROR: calculateAssemblyLength() input buffer too small: %d bytes. required length: %d bytes.\r\n",buffer_length,length); length = -1; } return length; } // dump the state of the Fragmenter/Assembler void DataFragmenterAssembler::dump(void) { DBG("\r\nDUMP: Number of fragments: %d last_length=%d\r\n",this->m_num_fragments,this->m_last_fragment_length); for(int i=0;i<this->m_num_fragments;++i) { DBG("DUMP: Fragment[%d]=[%s] length=%d\r\n",i,this->m_fragments[i],strlen((const char *)this->m_fragments[i])); } DBG("\r\n"); }