Simple data buffer splitter and re-assembler.
Diff: DataFragmenterAssembler.cpp
- Revision:
- 0:12a931a6161c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DataFragmenterAssembler.cpp Thu Feb 12 20:00:36 2015 +0000 @@ -0,0 +1,217 @@ +/** + * @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"); + } + + + \ No newline at end of file