Home | History | Annotate | Download | only in src
      1 /* ------------------------------------------------------------------
      2  * Copyright (C) 1998-2009 PacketVideo
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
     13  * express or implied.
     14  * See the License for the specific language governing permissions
     15  * and limitations under the License.
     16  * -------------------------------------------------------------------
     17  */
     18 #include "level0.h"
     19 #include "h324utils.h"
     20 #include "h223.h"
     21 
     22 #define HDLC    0x7e
     23 #define NUM_ZERO_BIT_INSERTION_BUFFERS 32
     24 
     25 Level0PduParcom::Level0PduParcom()
     26 {
     27     iLogger = PVLogger::GetLoggerObject("3g324m.h223.Level0");
     28     iNumRecvBits = 0;
     29     iRecvBits = 0;
     30     iRecvByte = 0;
     31     iRecvBytePos = 0;
     32     iRecvByte0 = 0;
     33     iRecvByte0Pos = 0;
     34     iZeroBitRemovedOutputPos = 0;
     35     iZeroBitRemovedOutput = 0;
     36     iPduPosZeroRemoved = 0;
     37 
     38     iTxByte0 = 0;
     39     iTxByte0Pos = 0;
     40     iTxCheck0 = 0;
     41     iTxCheck0Pos = 0;
     42 
     43     uint8 HecCrc[18] =
     44     {
     45         0x00, 0x05, 0x07, 0x02, 0x03, 0x06, 0x04, 0x01,
     46         0x06, 0x03, 0x01, 0x04, 0x05, 0x00, 0x02, 0x07
     47     };
     48 
     49     oscl_memcpy(iHecCrc, HecCrc, 18);
     50 }
     51 
     52 void
     53 Level0PduParcom::Construct(uint16 max_outstanding_pdus)
     54 {
     55     // Do not Leave on allocation failure
     56     iPduFragmentAlloc.SetLeaveOnAllocFailure(false);
     57     iPduFragmentAlloc.size(NUM_ZERO_BIT_INSERTION_BUFFERS, H223_MAX_MUX_PDU_SIZE);
     58     // Do not Leave on allocation failure
     59     iHdrFragmentAlloc.SetLeaveOnAllocFailure(false);
     60     iHdrFragmentAlloc.size(max_outstanding_pdus, (uint16)H223GetMaxStuffingSz(H223_LEVEL0));
     61 }
     62 
     63 void Level0PduParcom::GetHdrFragment(OsclRefCounterMemFrag& frag)
     64 {
     65     frag = iHdrFragmentAlloc.get();
     66 }
     67 
     68 uint32
     69 Level0PduParcom::GetStuffing(uint8* pPdu, uint32 max_size, uint8 mux_code)
     70 {
     71     OSCL_UNUSED_ARG(mux_code);
     72     OSCL_UNUSED_ARG(max_size);
     73     uint8* pos = pPdu;
     74     for (unsigned i = 0; i < max_size; i++)
     75     {
     76         pos += AppendTxOctet(HDLC, pos);
     77     }
     78     return (uint16)(pos - pPdu);
     79 }
     80 
     81 PVMFStatus Level0PduParcom::CompletePdu(OsclSharedPtr<PVMFMediaDataImpl>& pdu, int8 MuxTblNum, uint8 pm)
     82 {
     83     uint8 flag = HDLC;
     84     // header
     85     OsclRefCounterMemFrag frag;
     86     pdu->getMediaFragment(0, frag);
     87     pdu->setMediaFragFilledLen(0, GetHeaderSz());
     88 
     89     uint8* pPdu = (uint8*)frag.getMemFragPtr();
     90     *pPdu = flag;
     91     *(pPdu + 1) = (uint8)(iHecCrc[MuxTblNum] << 5 | MuxTblNum << 1);
     92 
     93 
     94     OsclRefCounterMemFrag post_zb_frag = iPduFragmentAlloc.get();
     95     if (post_zb_frag.getMemFragPtr() == NULL)
     96     {
     97         PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "Level0PduParcom::CompletePdu Failed to allocate post_zb_frag"));
     98         return PVMFErrNoMemory;
     99     }
    100 
    101     uint8* pos = (uint8*)post_zb_frag.getMemFragPtr();
    102     pos += AppendTxOctet(flag, pos);
    103     pos += AppendTxOctet(flag, pos);
    104     pos += Insert0Octet(*(pPdu + 1), 8, pos);
    105 
    106     // write out the payload
    107     for (uint frag_num = 1; frag_num < pdu->getNumFragments(); frag_num++)
    108     {
    109         pdu->getMediaFragment(frag_num, frag);
    110         pos += Insert0((uint8*)frag.getMemFragPtr(), frag.getMemFragSize(), pos);
    111     }
    112     pos += AppendTxOctet(flag, pos);
    113     if (pm)
    114     {
    115         pos += Insert0Octet(1, 8, pos);
    116         pos += AppendTxOctet(flag, pos);
    117     }
    118     pos += AppendTxOctet(flag, pos);
    119 
    120     // replace current fragments with the zero bit inserted fragment
    121     pdu->clearMediaFragments();
    122     post_zb_frag.getMemFrag().len = pos - (uint8*)post_zb_frag.getMemFragPtr();
    123     if (post_zb_frag.getMemFrag().len)
    124     {
    125         pdu->appendMediaFragment(post_zb_frag);
    126     }
    127 
    128     return PVMFSuccess;
    129 }
    130 
    131 uint32 Level0PduParcom::Parse(uint8* bsbuf, uint32 bsbsz)
    132 {
    133     //PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"Level0PduParcom::Parse %d\n", bsbsz));
    134     //printBuffer(iDebug, bsbuf, bsbsz);
    135     SearchForHdlcFlag(bsbuf, bsbsz);
    136     return 0;
    137 }
    138 
    139 /* This function writes an octet to the zero bit stuffed tx bitstream.  If there is pending bits for zero bit check,
    140    they are flushed out first */
    141 uint16 Level0PduParcom::AppendTxOctet(uint8 octet, uint8* pos)
    142 {
    143     uint8* write_pos = pos;
    144     if (iTxCheck0Pos)
    145     {
    146         write_pos += AppendTxBits0(iTxCheck0Pos, iTxCheck0, write_pos);
    147         iTxCheck0Pos = 0;
    148         iTxCheck0 = 0;
    149     }
    150     write_pos += AppendTxBits0(8, octet, write_pos);
    151     return (uint16)(write_pos - pos);
    152 }
    153 
    154 /* Writes out bits to the output stream */
    155 uint16 Level0PduParcom::AppendTxBits0(unsigned num_bits, int bits, uint8* pos)
    156 {
    157     uint8* write_pos = pos;
    158     iTxByte0 |= (bits << iTxByte0Pos);
    159     iTxByte0Pos += num_bits;
    160 
    161     while (iTxByte0Pos >= 8)
    162     {
    163         *write_pos++ = (uint8)iTxByte0;
    164         iTxByte0 >>= 8;
    165         iTxByte0Pos -= 8;
    166     }
    167     return (uint16)(write_pos - pos);
    168 }
    169 
    170 /* Inserts the octet while checking for 5 1's.  */
    171 uint16 Level0PduParcom::Insert0Octet(uint8 octet, uint16 num_bits_from_octet, uint8* out_buffer)
    172 {
    173     uint8* write_pos = out_buffer;
    174 
    175     iTxCheck0 = iTxCheck0 | (octet << iTxCheck0Pos);
    176     iTxCheck0Pos += num_bits_from_octet;
    177     int bits_consumed = 0;
    178     while (iTxCheck0Pos >= 5)
    179     {
    180         if ((iTxCheck0 & 0x1F) == 0x1F)
    181         {
    182             // 5 1's detected.  Insert 0 after them
    183             //PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"Level0PduParcom::Insert0Octet - inserting 0\n"));
    184             write_pos += AppendTxBits0(5, iTxCheck0 & 0x1F, write_pos);
    185             write_pos += AppendTxBits0(1, 0, write_pos);
    186             bits_consumed = 5;
    187         }
    188         else
    189         {
    190             // just insert the lsb
    191             write_pos += AppendTxBits0(1, iTxCheck0 & 1, write_pos);
    192             bits_consumed = 1;
    193         }
    194         iTxCheck0 >>= bits_consumed;
    195         iTxCheck0Pos -= bits_consumed;
    196     }
    197     return (uint16)(write_pos - out_buffer);
    198 }
    199 
    200 /* Zero bit insertion from a buffer */
    201 uint16
    202 Level0PduParcom::Insert0(uint8* chunk, int chunk_size, uint8* out_buffer)
    203 {
    204     uint8* pos = out_buffer;
    205     for (int bytenum = 0; bytenum < chunk_size; bytenum++)
    206     {
    207         pos += Insert0Octet(chunk[bytenum], 8, pos);
    208     }
    209     return (uint16)(pos - out_buffer);
    210 }
    211 
    212 /* Does more than the name implies.  It searches for the next flag, and if a valid pdu is found, does zero bit removal
    213    and indicates pdu to upper layer */
    214 void Level0PduParcom::SearchForHdlcFlag(uint8* bsbuf, int bsbsz)
    215 {
    216     for (int bytenum = 0; bytenum < bsbsz; bytenum++)
    217     {
    218         uint8 cur_byte = bsbuf[bytenum];
    219         uint8 cur_bit = 0;
    220         for (int bitnum = 0; bitnum < 8; bitnum++)
    221         {
    222             cur_bit = (uint8)(cur_byte & 0x1);
    223             cur_byte >>= 1;
    224             iRecvBits = (uint8)(iRecvBits | (cur_bit << iNumRecvBits++));
    225             if (iNumRecvBits == 8)
    226             {
    227                 if ((iRecvBits&HDLC) == HDLC)
    228                 {
    229                     // found flag
    230                     unsigned size = iPduPos - iPdu;
    231                     if (size)
    232                     {
    233                         // perform 0 bit removal within the same buffer
    234                         Remove0();
    235                     }
    236                     iNumRecvBits = 0;
    237                     iRecvBits = 0;
    238                 }
    239                 else
    240                 {
    241                     // copy current bit to pdu
    242                     AppendBit(iRecvBits&0x1);
    243                     iRecvBits >>= 1;
    244                     iNumRecvBits--;
    245                 }
    246             }
    247         }
    248     }
    249 }
    250 
    251 /* Appends a bit to the received bitstream.  If 8 bits are received, they are flushed to iPdu */
    252 void Level0PduParcom::AppendBit(int c)
    253 {
    254     iRecvByte |= (c << iRecvBytePos++);
    255     if (iRecvBytePos == 8)
    256     {
    257         if (iPduPos == iPduEndPos)
    258         {
    259             Remove0();
    260         }
    261         *iPduPos++ = (uint8)iRecvByte;
    262         iRecvByte = 0;
    263         iRecvBytePos = 0;
    264     }
    265 }
    266 
    267 /* Appends bits to the zero bit removed incoming bitstream */
    268 void Level0PduParcom::AppendBits0(unsigned num_bits, int bits)
    269 {
    270     iZeroBitRemovedOutput = iZeroBitRemovedOutput | (bits << iZeroBitRemovedOutputPos);
    271     iZeroBitRemovedOutputPos += num_bits;
    272     while (iZeroBitRemovedOutputPos >= 8)
    273     {
    274         OSCL_ASSERT(iPduPosZeroRemoved != (iPduEndPos + 1));
    275         *iPduPosZeroRemoved++ = (uint8)iZeroBitRemovedOutput;
    276         iZeroBitRemovedOutput >>= 8;
    277         iZeroBitRemovedOutputPos -= 8;
    278     }
    279 }
    280 
    281 /* Performs 0 bit removal from the current pdu (iPdu) */
    282 unsigned Level0PduParcom::Remove0()
    283 {
    284     int size = iPduPos - iPdu;
    285     OSCL_ASSERT(size >= 0);
    286     iPduPosZeroRemoved = iPdu;
    287     //PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"Level0PduParcom::Remove0 size(%d)", size));
    288     for (int bytenum = 0; bytenum < size; bytenum++)
    289     {
    290         Remove0Octet(iPdu[bytenum], 8);
    291     }
    292     if (iRecvBytePos)
    293     {
    294         //PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"Level0PduParcom::Remove0 iRecvBytePos(%d)", iRecvBytePos));
    295         Remove0Octet((uint8)iRecvByte, iRecvBytePos);
    296         iRecvBytePos = 0;
    297         iRecvByte = 0;
    298     }
    299     if (iRecvByte0Pos)
    300     {
    301         //PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"Level0PduParcom::Remove0 iRecvByte0Pos(%d)", iRecvByte0Pos));
    302         AppendBits0(iRecvByte0Pos, iRecvByte0);
    303         iRecvByte0Pos = 0;
    304         iRecvByte0 = 0;
    305     }
    306     //OSCL_ASSERT(iZeroBitRemovedOutputPos == 0);
    307     if (iZeroBitRemovedOutputPos)
    308     {
    309         PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_WARNING, (0, "Level0PduParcom::Remove0 Error - iZeroBitRemovedOutputPos(%d) != 0", iZeroBitRemovedOutputPos));
    310         iZeroBitRemovedOutputPos = 0;
    311     }
    312     /* Return MUX-PDU header data */
    313     int fClosing = 0;
    314     int muxCode = -1;
    315     iPduPos = iPdu;
    316     if (*iPduPos & 1)
    317     {
    318         fClosing = 1;
    319     }
    320     muxCode = (*iPduPos >> 1) & 0xf;
    321     iPduPos++;
    322     iObserver->MuxPduIndicate(iPduPos, (uint16)(iPduPosZeroRemoved - iPdu - 1), fClosing, muxCode);
    323 
    324     iPduPos = iPdu;
    325     return 0;
    326 }
    327 
    328 void Level0PduParcom::Remove0Octet(uint8 cur_byte, int num_bits_from_octet)
    329 {
    330     uint8 cur_bit = 0;
    331     for (int bitnum = 0; bitnum < num_bits_from_octet; bitnum++)
    332     {
    333         cur_bit = (uint8)(cur_byte & 0x1);
    334         cur_byte >>= 1;
    335         iRecvByte0 = (uint8)(iRecvByte0 | (cur_bit << iRecvByte0Pos++));
    336         if (iRecvByte0Pos == 6)
    337         {
    338             if ((iRecvByte0 & 0x1F) == 0x1F)
    339             {
    340                 //PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"Level0PduParcom::Remove0Octet - skipping 0\n"));
    341 //              OSCL_ASSERT( (iRecvByte0 & 0x20) == 0);
    342                 if ((iRecvByte0&0x20) != 0)
    343                 {
    344                     PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "Level0PduParcom::Remove0Octet - Bitstream error.\n"));
    345                 }
    346                 // write out 5 1's and skip the following 0 bit
    347                 AppendBits0(5, 0x1F);
    348                 iRecvByte0Pos = 0;
    349                 iRecvByte0 = 0;
    350             }
    351             else
    352             {
    353                 // write out the lsb
    354                 AppendBits0(1, iRecvByte0&01);
    355                 iRecvByte0Pos--;
    356                 iRecvByte0 >>= 1;
    357             }
    358 
    359         }
    360     }
    361 }
    362