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