/*
* Mobicents, Communications Middleware
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party
* contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
*
* Boston, MA 02110-1301 USA
*/
package org.mobicents.media.server.impl.resource.zap;
/**
*
* @author kulikov
*/
public class HDLCChannel {
public final static int STATE_OCTET_COUNTING = 0;
public final static int STATE_DATA_READING = 1;
private HDLCReader reader;
private int state = STATE_OCTET_COUNTING;
private byte[] data = new byte[279];
private int seg = 0;
private int offset = 0;
private int buff;
private int[] stamp = new int[256];
private int[] mask = new int[]{1, 3, 7, 15, 31, 63, 127, 255};
private int[][][]ones = new int[8][256][2];
private int bits = 0;
public HDLCChannel() {
for (int i = 1; i < 7; i++) {
int n = (int) Math.pow(2, i);
for (int p = 0; p < n; p++) {
int q = (p << (8 - i)) | (0x7e >> i);
stamp[q] = i;
}
}
for (int i = 1; i < 8; i++) {
}
}
public void setReader(HDLCReader reader) {
this.reader = reader;
}
public int getState() {
return state;
}
public void offer(byte b) {
if (b == 0x7e) {
if (state == STATE_OCTET_COUNTING) {
state = STATE_DATA_READING;
} else {
this.push();
}
} else //there was no any indications of the boundary flag in the previous byte
if (bits == 0) {
//checking if flag indications is presented in this byte
bits = stamp[b & 0xff];
if (bits > 0) {
//found the begining of the flag, the next one can contains
//the remainder part. let's save current byte in the local buffer
buff = (buff << 8) | b;
} else {
//there is no flag's indications in the current byte too.
//then it is a data. we are appending to a data array if state
//is reading data or ignore if state is octet counting
if (state == STATE_DATA_READING) {
append(b, 8);
}
}
} else {
//the previous byte contains flag's indications
//let's try to find ending part in the current byte
int p = (b & 0xff) >> (8 - bits);
int q = 0x7e & mask[bits - 1];
if (p == q) {
//yes, flag is detected
//the action now depends from the state of the channel.
//if state is octet counting, we should swicth state and append
//bits followed by the flag to the data stream. if state is data
//reading then this flag is frame boundary. we have to append
//bits received before flag to the data stream, push data stream
//to the receiver and append bits followed by the flag to the stream
switch (state) {
case STATE_OCTET_COUNTING :
append(b, bits);
state = STATE_DATA_READING;
break;
case STATE_DATA_READING :
buff >>= 8-bits;
append((byte)buff, bits);
push();
append(b, bits);
bits = 0;
break;
}
} else {
//no, it is not a flag but the prevoius byte now local buffer
//we should append it to the data stream.
append((byte)buff, 8);
append(b, 8);
}
bits = 0;
}
}
/**
* Appends last <code>count</code> bits to the data stream.
*
* @param buff the the local buffer which contains bits to append
* @param count the number of bits to append.
*/
private void append(byte buff, int count) {
int available = 8 - offset;
if (count <= available) {
data[seg] |= (buff & mask[count-1]) << (available - count);
offset += count;
if (offset == 8) {
offset = 0;
seg++;
}
} else {
int dif = (count - available);
data[seg] |= ((buff & mask[count-1]) >> dif);
seg++;
offset = 0;
data[seg] = (byte)((buff & mask[count-1]) << (8 - dif));
offset += dif;
}
}
private void push() {
if (offset != 0) {
state = STATE_OCTET_COUNTING;
return;
}
if (this.reader != null) {
reader.receive(data, seg);
}
for (int i = 0; i < seg; i++) {
data[i] = 0;
}
seg = 0;
offset = 0;
}
public static void main(String[] args) {
byte[] stream = new byte[]{(byte)0x7e, 0x01, 0x01, 0x00, (byte)0x37, (byte)0x62, (byte)0x7e};
HDLCChannel ch = new HDLCChannel();
for (int i = 0; i < stream.length; i++) {
ch.offer(stream[i]);
}
}
}