[rec.ham-radio.packet] Asynchronous Framing Technique

n2dsy@hou2d.UUCP (G.BEATTIE) (04/11/88)

OK Folks !

I have received several notes and messages about the
distribution of our software and documents via the net.
Let's understand a few basic points here:

ISSUE: I don'thave access to ftp to outside systems from hou2d.

If someone has such a package with source for a 3B1 and sends me a
DISK, I will get it going.  I think I can get a network connection
at NJIT, but I will entertain other offers.

ISSUE: Hate mail for using the net for distribution.

The response has been as follows:
2 mailer generated messages signalling error.
2 human generated messages saying No Good.
6 human generated messages saying Thanks.

I wished every comment I make on the net could fair this well!
One interesting note: one of the messages that said "Don't do
it" came from an individual who doesn't like AFT and is
PUSHING SLIP...

I will re-examine the distribution mechanism and see what makes sense.
I will probably forward out the code through "comp.protocols.iso"
in the future.  I will continue to send out documents and announcements
via several groups.

Comments?


Thanks,
            J. Gordon Beattie, Jr.
E-mail:    ihnp4!hou2d!n2dsy (Unix)  n2dsy@kd6th.a3100201.ampr
Telephone: 201-615-4168 (Office)     201-615-4669 (Office FAX)
Telephone: 201-387-8896 (Home)

n2dsy@hou2d.UUCP (G.BEATTIE) (04/13/88)

/*
	Machine Independent Asynchronous Framing Technique (AFT)


            Version 1.0, by John Howell (N2FVN), Copyright August 7, 1987
               
            This software is free for non-commercial use.  All commercial
            rights are retained by the author or his designees.  Commercial 
            use without the explicit written permission of the author is
            prohibited.  This package is provided on an 'as is' basis 
            without warranty.
	

*/

		/* Macros */

#define	FLAG		0x007E
/* 
	This is the flag character which is used to start and end
	frames.  The send generates separate starting and ending flag
	characters, but the receiver can accept a single flag to end one
	frame and start another.
*/


#define	LEAD_IN		0x007D
/*
	This is the lead in character which is used when transparency is
	required.  When the receiver detects this character it takes the
	following character and exclusive ors it with 0x20 to produce
	the proper character.  This is used to allow the transmission of
	characters which would not otherwise be received properly.
*/


#define	TRANSPARENT(c)	(c ^ 0x20)
/*
	This is the function to be performed to convert a character into
	one which may be transmitted transparently.  This is also used
	to return a character to its original value since the function
	is its own inverse.
*/


#define	IDLE_CODE	(0x0100 + FLAG)
/*
	This is the idle code with is returned by aft_tx_char when it
	has no frame to send.  The high order byte indicates completion
	and the low order byte is a flag which might be sent if flags
	are to be used between frames as filler.
*/


#define	GENERATOR	0x8408
/*
	This is the generator polynomial for the frame check sequence.
	The polynomial is the standard CCITT polynomial.  It is in
	reverse bit order for faster calculation.  The polynomial is
	X**16 + X**12 + X**5 + 1.
*/


#define	EXPECT_FCS	0xF0B8
/*
	This is the expected final FCS for a correctly received frame.
*/


#define	OK		1
/*
	This is the return code used by some routines to indicate
	successful completion.
*/


#define	NO_GOOD		0
/*
	This is the return code used by some routines to indicate
	unsuccessful completion.
*/



/* Global declarations */


static char opt_ebdt;
/*
	This is a flag controlling the use of eight-bit data
	transparency on transmitted and receive frames.
*/


static char opt_transparency_level;
/*
	This is the transparency level to be used when transmitting
	frames (0-2).  Each increasing level causes more characters to
	be avoided when sending frames which allows them to be sent in
	situations where certain characters are not allowed.
*/


static char opt_suffix_len;
static unsigned char opt_suffix[3];
/*
	This is the suffix string to be added to the end of each frame
	sent.  Any character including a null is allowed.
*/


static unsigned int opt_max_rx_len;
/*
	This is the maximum size of a receive buffer.  It is used when
	receiving to make sure that a received frame does not go past
	the end of the buffer.  A received frame which is too long will
	be discarded.
*/

static unsigned char transparency_level [256] = {
	
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 2,

	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
	9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9};
/*
	For each possible character this is the transparency level at
	which it should be encoded for transparency.  A value of nine is
	used for character which should never be encoded.
*/


		/* Variables and macros used by aft_tx_char */

static char tx_char_state;
/*
	This is the state of the transmission routine which handles
	transparency, delimiting of frames, and frame abort.  It is used
	to determine the next action to be performed by aft_tx_char when
	it is called.  State names are given by the 'TCS_' macros.
*/


#define TCS_IDLE		0
/*
	This state indicates that no frame is being sent.  Calls to
	aft_tx_char while in this state return the idle code and calls
	to aft_tx_complete return one.  This is the only state in which
	a call to aft_tx_start is valid.
*/


#define TCS_START_FLAG		1
/*
	This state indicates that the starting flag for a frame should
	be sent when aft_tx_char is next called.  This state is entered
	when aft_tx_start accepts a frame to be sent.
*/


#define TCS_GET_NEXT_CHAR	2
/*
	This state indicates that the next character to be sent should
	be gotten by calling tx_ebdt.  Before being sent the character
	will be checked against a table to see if a substitution is
	required.  If so then the current character is saved and a
	lead-in character is sent.
*/


#define TCS_SUBSTITUTE_CHAR	3
/*
	This state indicates that the next character to be sent is the
	encoded value of the current character.  This is used for
	transparency purposes.
*/


#define TCS_SUFFIX		4
/*
	This state is used when the closing flag has been sent to
	indicate the need to send any additional defined suffix
	characters at the end of the frame.  Once all suffix characters
	have been sent the transmitter returns to the TCS_IDLE state.
*/


#define TCS_ABORT_LEAD_IN	5
/*
	This state indicates that the caller has decided to abort the
	frame before it has been completely sent.  A lead in character
	followed by a flag will be sent to indicate that the receiver
	should discard the frame.
*/


#define TCS_ABORT_FLAG		6
/*
	The lead-in character has been sent to abort the current frame.
	A flag will be now sent to complete the abort sequence.
*/


static unsigned char tx_encode_char;
/*
	This is the character to be sent after it is encoded for
	transparency.  The value is saved here while waiting for
	aft_tx_char to be sent after it has returned the transparency
	lead-in character.
*/


static char tx_suffix_count;
/*
	This is a count of the number of suffix characters which have
	been sent so far at the end of the frame.
*/


		/* Variables and macros used by  tx_ebdt */

static char tx_ebdt_state;
/*
	This is the state of the eight bit data transparency routines.
	The value is actually a count of the number of characters which
	have each contributed their high order bit to the tx_ebdt_char.
	It is reset back to zero when the ebdt character is sent.
*/


static unsigned char tx_ebdt_char;
/*
	This is the character being built up from the high order bits of
	other characters during transmission when eight-bit data
	transparency is enabled.  This will be sent once either seven
	bits have been collected or the frame ends.
*/


		/* Variables and macros used by tx_data */

static char tx_data_state;
/*
	This is the state of the routines which get data from the
	transmit buffer, calculate the frame check sequence, and send
	the frame check sequence.  State names are given by the 'TDS_'
	macros.
*/


#define TDS_GET_FROM_BUFFER	0
/*
	This state indicates that the next character to be sent should
	be gotten from the transmit buffer.  The FCS is updated based on
	the character gotten.  Once all characters from the buffer have
	been sent the FCS will be sent.
*/


#define TDS_FCS_ONE		1
/*
	This state indicates that sending of characters from the buffer
	has completed and that the next character to be sent is the
	first half of the frame check sequence.
*/


#define TDS_FCS_TWO		2
/*
	This state indicates that the first half of the FCS has been
	sent and so the second half should be sent next.
*/


#define TDS_COMPLETE		3
/*
	This state indicates that sending of the FCS is complete.
*/



static unsigned char *tx_buffer;
static unsigned int tx_len_remaining;
/*
	tx_buffer is a pointer to the next character to be sent from the
	transmit buffer provided by the caller of aft_tx_start.  It is
	incremented as each character is used from the buffer.  The
	length remaining field is decremented as each character is used.
	When it reaches zero all characters from the supplied buffer
	have been sent and FCS transmission may begin.
*/


static unsigned int tx_fcs;
/*
	This is the two bytes of the frame check sequence (FCS) to be
	sent at the end of the frame being transmitted stored in reverse
	bit order for easier transmission.  The FCS is initialized to
	all ones before the frame is transmitted.  As the frame is sent
	the FCS is calculated using the algorithm specified in CCITT
	X.25 using each character as it is obtained from the transmit
	buffer.
*/


		/* Variables and macros for aft_rx_char */

static unsigned char rx_char_state;
/*
	This is the state of the main reception routine.  It is used to
	determine the next action performed by aft_rx_char when it is
	called.  State names are given by the 'RCS_' macros.
*/


#define RCS_IDLE			0
/*
	This state indicates that no buffer has been provided for
	reception.  Received characters are ignored while in this state.
*/


#define RCS_START_FLAG			1
/*
	This state indicates that a buffer has been provided to the
	receive routines and we are waiting to receive the opening flag
	for a frame.  Non-flag characters will be ignored in this state.
*/


#define RCS_AWAIT_NEXT_CHAR		2
/*
	This state indicates that the opening flag has been received and
	characters are being received into the frame buffer.  If the
	character received is the ending flag then the frame size and
	FCS are verified otherwise the chracter is passed to the
	eight-bit data transparency routine for processing.
*/


#define RCS_AWAIT_SUBSTITUTE_CHAR	3
/*
	This state indicates that we have received a lead in character
	and are now expecting another character which will decoded and
	sent to the EBDT routines.  If the character received is a flag
	then this indicates that the sender is aborting the frame so it
	should be discarded.
*/


static int rx_ebdt_state;
/*
	This is the number of characters received since the last eight
	bit data transparency character.  This will reach eight when the
	next EBDT character is received.  If the frame ends with this
	count non-zero then the character just received is the EBDT
	character for a group of less than seven bytes.
*/


static unsigned char rx_ebdt_save[7];
/*
	This array is used to buffer a maximum of seven characters when
	eight bit data transparency is being used.  When the EBDT
	character is received then each saved character is modified to
	have the correct eighth bit and transferred to the receive
	buffer.
*/


static unsigned char *rx_buffer;
/*
	rx_buffer holds the pointer to the start of the receive buffer.
*/


static int rx_len, rx_final_len;
/*
	rx_len is the number of characters received so far in the
	current frame.  rx_final_len is initialized to zero and set to
	the final frame length once the frame has been completely
	received.
*/


static unsigned int rx_fcs;
/*
	This is the two bytes of the receive frame check sequence stored
	in reverse bit order.  It is calculated as characters are
	received using the same method as that used for tx_fcs.  At the
	end of the frame this must match the expected value or the frame
	is invalid.
*/






aft_options(	o_ebdt, o_transparency_level, 
		o_suffix_len, o_suffix, o_max_rx_len)

char o_ebdt;			/* Eight-bit data xparency (nonzero) */
char o_transparency_level;	/* zero to two */
char o_suffix_len;		/* zero to three */
char o_suffix[3];		/* suffix string to be sent */
int  o_max_rx_len;		/* size of rx buffers */
{
	int count;		/* Suffix character count */

	/* Initialize internal state variables */

	tx_char_state = TCS_IDLE;

	rx_char_state = RCS_IDLE;
	rx_final_len = 0;

	/* Save selected options */

	opt_ebdt = o_ebdt;
	opt_transparency_level = o_transparency_level;
	opt_suffix_len = o_suffix_len;
	
	for (count = 0; count < sizeof(opt_suffix); count++)
		opt_suffix[count] = o_suffix[count];

	opt_max_rx_len = o_max_rx_len;
}



int aft_tx_start(length, buffer)

unsigned int length;		/* length of the buffer */
unsigned char *buffer;		/* buffer pointer */
{

	/* Only allow if transmitter is idle and frame is valid */

	if ((tx_char_state != TCS_IDLE) || (length < 2))
		return NO_GOOD;

	/* Set internal state variables for transmission */

	tx_data_state = TDS_GET_FROM_BUFFER;

	tx_buffer = buffer;		/* Save pointer to next char */
	tx_len_remaining = length;

	tx_fcs = 0xFFFF;		/* Set all FCS bits to one. */

	tx_ebdt_state =			/* No EBDT char being built */
	tx_ebdt_char = 

	tx_suffix_count = 0;		/* No suffix characters sent yet. */

	/* 
		Now that all is ready the state can be changed.  This
		could not be done before since aft_tx_char might have
		been called before setup was complete.  It is assumed
		that since the state is a 'char' it can be assigned
		while interrupts are enabled since it will be changed
		with a single write to memory.

		The state is set so that the starting flag will be the
		next character sent.
	*/

	tx_char_state = TCS_START_FLAG;

	return OK;			/* successful return */
}



int aft_tx_char()
{
	int c;		/* The character to be sent */

	/*
		This routine is responsible for returning each character
		to be sent over the communication line.  It handles
		generation of starting and ending flags, data
		transparency, suffix character generation, and frame
		abort generation.  tx_ebdt is called to determine data
		characters to be sent.
	*/

	switch (tx_char_state) {

		case TCS_IDLE:
			c = IDLE_CODE;
			break;

		case TCS_START_FLAG:
			/*
				We are starting to send out a new frame.
				Send out the starting flag before any
				data.
			*/
			c = FLAG;
			tx_char_state = TCS_GET_NEXT_CHAR;
			break;

		case TCS_GET_NEXT_CHAR:
			c = tx_ebdt();		/* Get next character */

			if (c == IDLE_CODE) {
				/*
					The entire frame has been sent.  
					Delimit with a flag.
				*/
				c = FLAG;

				if (opt_suffix_len > 0)
					tx_char_state = TCS_SUFFIX;
				else
					tx_char_state = TCS_IDLE;
			}
			else {
				if (transparency_level[c]
				    <= opt_transparency_level) {
					/*
						This character cannot be 
						sent.  Use transparency.
					*/
					tx_encode_char = c;
					c = LEAD_IN;
					tx_char_state = TCS_SUBSTITUTE_CHAR;
				}
			}
			break;

		case TCS_SUBSTITUTE_CHAR:
			c = TRANSPARENT(tx_encode_char);
			tx_char_state = TCS_GET_NEXT_CHAR;
			break;

		case TCS_SUFFIX:
			c = opt_suffix[tx_suffix_count++];

			if (tx_suffix_count >= opt_suffix_len)
				tx_char_state = TCS_IDLE;

			break;

		case TCS_ABORT_LEAD_IN:
			c = LEAD_IN;
			tx_char_state = TCS_ABORT_FLAG;
			break;

		case TCS_ABORT_FLAG:
			c = FLAG;
			tx_char_state = TCS_IDLE;
	}

	return c;
}


static int tx_ebdt()
{
	int c;				/* Character to be returned */

	/*
		This routine handles eight-bit data
		transparency.  If enabled the high order bit of
		each character returned by tx_data is removed
		and added to an eight-bit data transparency
		character.  Once this character has collected
		seven bits or the frame ends this character is
		sent.  Doing this allows the receiver to recover
		the high order bits from the previous characters
		sent.
	*/

	if (!opt_ebdt) {
		/*
			If eight bit data transparency is not being 
			used then this is just a pass through.  If 
			this option is never used then this routine 
			may be completely eliminated for efficiency.
		*/
		c = tx_data();
	}
	else {
		if (tx_ebdt_state == 7) {
			/*
				There is a full collection of seven 
				high order bits ready to be sent.
			*/
			c = tx_ebdt_char;
			tx_ebdt_char =
			tx_ebdt_state = 0;
		}
		else {
			c = tx_data();

			if (c != IDLE_CODE) {
				/*
					Append the high order bit from 
					the character to be sent to the 
					EBDT character.
				*/

				tx_ebdt_char = (tx_ebdt_char << 1) + 
							((c & 0x80) != 0);

				c = c & 0x7F;
				tx_ebdt_state++;
			}
			else {
				/*
					The end of the frame has been 
					reached.  If there have been any 
					high order bits collected then 
					send one last EBDT character.
				*/
				if (tx_ebdt_state != 0) {
					c = tx_ebdt_char << 
						(7 - tx_ebdt_state);

					tx_ebdt_char =
					tx_ebdt_state = 0;
				}
				else {
					c = IDLE_CODE;
				}
			}
		}
	}
	return c;
}


static int tx_data()
{
	int c;				/* Character to be returned */
	char tx_bits, bit_count;	/* For FCS calculation */

	/*
		The next character is obtained from the transmit 
		buffer and the FCS calculated.  Once all character 
		from the buffer have been sent, the FCS is also sent.
	*/

	switch (tx_data_state) {

		case TDS_GET_FROM_BUFFER:

			c = *(tx_buffer++);

			/* FCS calculation */

			tx_bits = c;
			for (bit_count = 0; bit_count < 8; bit_count++) {
				if ((tx_fcs ^ tx_bits) & 1)
					tx_fcs = (tx_fcs >> 1) ^ GENERATOR;
				else
					tx_fcs = tx_fcs >> 1;
				tx_bits = tx_bits >> 1; 
			}

			if (--tx_len_remaining == 0)
				tx_data_state = TDS_FCS_ONE;

			break;

		case TDS_FCS_ONE:
			/*
				Send the first character of the
				frame check sequence.  The bits
				are inverted before sending.
			*/
			c = (~tx_fcs) & 0x00ff;;
			tx_data_state = TDS_FCS_TWO;
			break;

		case TDS_FCS_TWO:
			/*
				Send the second character of the
				frame check sequence.  The bits
				are inverted before sending.
			*/
			c = (~tx_fcs) >> 8;
			tx_data_state = TDS_COMPLETE;
			break;

		case TDS_COMPLETE:
			c = IDLE_CODE;
			break;
	}

	return c;
}


aft_tx_abort()
{
	/*
		If aft_send_char is being called from within an
		interrupt service routine and this routine is
		intended to be used then interrupts must be
		disabled when this routine is called.

		The current state is changed to cause an abort
		sequence to be sent to receiver.
	*/

	switch (tx_char_state) {

		case TCS_START_FLAG:
			tx_char_state = TCS_IDLE;
			break;

		case TCS_GET_NEXT_CHAR:
			tx_char_state = TCS_ABORT_LEAD_IN;
			break;

		case TCS_SUBSTITUTE_CHAR:
			tx_char_state = TCS_ABORT_FLAG;
			break;

		default:
			break;
	}
}


int aft_tx_complete()
{
	return (tx_char_state == TCS_IDLE);
}



int aft_rx_start(buffer)
unsigned char *buffer;
{
	/*
		Provide a buffer to start receiving the next
		frame into.  If we are already receiving then
		the request is rejected.
	*/

	if (rx_char_state != RCS_IDLE)
		return NO_GOOD;

	/*
		Save the pointer to the buffer and set up for receive.
	*/

	rx_buffer = buffer;

	aft_rx_error();		/* Reset the receive routines */

	rx_char_state = RCS_START_FLAG;

	return OK;
}


aft_rx_error()
{
	/*
		Return to the condition of waiting for the starting flag.  
	*/

	rx_len =
	rx_final_len =
	rx_ebdt_state = 0;

	rx_fcs = 0xffff;

	if (rx_char_state != RCS_IDLE)
		rx_char_state = RCS_START_FLAG;
}


int
aft_rx_complete()
{
	return rx_final_len;
}


int aft_rx_char(c)
unsigned char c;
{

	/*
		Add the next character to the receive buffer
		depending on the current state.
	*/

	if (opt_ebdt) {
		/*
			Ignore the high order bit of the
			character if it cannot be received
			transparently.
		*/
		c = c & 0x7f;
	}

	switch (rx_char_state) {

		case RCS_IDLE:
			/*
				If no buffer has been provided
				then ignore characters.
			*/
			break;

		case RCS_START_FLAG:
			/*
				In this state we are hunting for
				a flag.  If this is a flag then
				the receive operation may begin.
			*/

			if (c == FLAG)
				rx_char_state = RCS_AWAIT_NEXT_CHAR;

			break;

		case RCS_AWAIT_NEXT_CHAR:

			if (c == LEAD_IN) {
				rx_char_state = RCS_AWAIT_SUBSTITUTE_CHAR;
			}
			else {
				if (c == FLAG) {

					rx_finish_ebdt();

					/*
						If the frame is
						too short or the
						FCS is not
						correct then the
						frame is
						discarded.
					*/

					/* For FCS */
					rx_final_len = rx_len - 2; 

					if (rx_final_len >= 2 && 
					    rx_fcs == EXPECT_FCS)
						rx_char_state = RCS_IDLE;
					else
						aft_rx_error();
				}
				else {
					rx_ebdt(c);
				}
			}
			break;

		case RCS_AWAIT_SUBSTITUTE_CHAR:
			/*
				Handle the character which
				follows a lead-in character.  If
				it is a flag then this is a
				frame abort and so the frame is
				ignored.  Otherwise translate
				the character and add it to the
				buffer.
			*/

			if (c != FLAG) {
				rx_ebdt(TRANSPARENT(c));
				rx_char_state = RCS_AWAIT_NEXT_CHAR;
			}
			else {
				aft_rx_error();
			}
			break;
	}

	return rx_final_len;
}



rx_ebdt(c)
unsigned char c;
{
	int bit_count;

	/*
		This routine handles received characters which
		have passed the normal substitution process.  It
		handles the eight-bit data transparency by
		saving characters until the transparency
		character is detected and then adding the
		correct high order bit to each of the
		characters.
	*/
	if (!opt_ebdt) {
		rx_data(c);
	}
	else {

		if (rx_ebdt_state >= 7) {
			
			for (bit_count = 0;
				(bit_count < 7) &&
				(rx_ebdt_state != 0);
				bit_count ++) {

				c = c << 1;
				rx_data(rx_ebdt_save[bit_count] | 
					(c & 0x80));
			}

			rx_ebdt_state = 0;
		}
		else {
			rx_ebdt_save[rx_ebdt_state++] = c;
		}
	}
}


rx_finish_ebdt()
{
	unsigned char c;
	int bit_count;

	/*
		This routine finishes any pending EBDT conversion
		when the end of the frame is detected.
	*/

	if (opt_ebdt && rx_ebdt_state > 0) {
		c = rx_ebdt_save[--rx_ebdt_state];

		for (bit_count = 0;
			(bit_count < rx_ebdt_state) &&
			(rx_ebdt_state != 0);
			bit_count ++) {

			c = c << 1;
			rx_data(rx_ebdt_save[bit_count] | 
				(c & 0x80));
		}

		rx_ebdt_state = 0;
	}
}


rx_data(c)
unsigned char c;
{
	int bit_count;
	unsigned char rx_bits;

	/* FCS calculation */

	rx_bits = c;
	for (bit_count = 0; bit_count < 8; bit_count++) {
		if ((rx_fcs ^ rx_bits) & 1)
			rx_fcs = (rx_fcs >> 1) ^ GENERATOR;
		else
			rx_fcs = rx_fcs >> 1;

		rx_bits = rx_bits >> 1; 
	}

	if (rx_len == opt_max_rx_len) {
		aft_rx_error();
	}
	else {
		*(rx_buffer + (rx_len++)) = c;
	}
}