uart-packet-dle.c 7.7 KB
/**    
    @file     uart-packet-dle.h
    @date     2010-09-17
    @author   오재경 freefrug@falinux.com
    @brief    uart 통신형태를 분석하고 관리한다.
              
              dle / stx / data(crc16) / dle / etx

    @modify   
    @todo    
    @bug     
    @remark   
    
    @warning 
*/
//
//  저작권    에프에이리눅스(주)
//            외부공개 금지
//
//----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/un.h> 
#include <termios.h>

#include <pollmng.h>
#include <uart.h>
#include <crc16.h>
#include <uart-packet-dle.h>

char desc_uart_packet_dle[] = "falinux uart-packet-dle ver 0.1.0";


#define  TRACE()  printf( ".. %s(%d)\n", __FUNCTION__,__LINE__ )

//------------------------------------------------------------------------------
/** @brief    기본 crc16 함수
    @param    buf    데이타버퍼
    @param    count  데이타개수
    @return   복사된 데이타 길이
*///----------------------------------------------------------------------------
static unsigned short upacket_dle_def_make_crc16( char *buf, int count )
{
	return crc16_ccitt( buf, count );
}

//------------------------------------------------------------------------------
/** @brief    uart 패켓 관린 객체 생성
    @param    obj  uart 폴객체 포인터
    @param    callback  패켓이 만들어졌을대 호출되는 함수
*///----------------------------------------------------------------------------
void  upacket_dle_create( poll_obj_t *obj, on_uart_packet_t callback )
{
	uart_packet_analysis_t  *up;
	
	up = (uart_packet_analysis_t *)malloc( sizeof(uart_packet_analysis_t) );
	memset( (void *)up, 0, sizeof(uart_packet_analysis_t) );
	
	up->obj = obj;
	up->stx = 0x02;	
	up->etx = 0x03;
	up->dle = 0x10;
	up->make_crc16 = upacket_dle_def_make_crc16;
	up->on_packet  = callback;
	
	upacket_dle_clear( up );
	
	obj->user = (void *)up;
}
//------------------------------------------------------------------------------
/** @brief    uart 패켓 관린 객체 해제
    @param    obj  uart 폴객체 포인터
*///----------------------------------------------------------------------------
void  upacket_dle_free( poll_obj_t *obj )
{
	if ( obj->user ) free( obj->user );
	obj->user = NULL;
}
//------------------------------------------------------------------------------
/** @brief    uart 패켓분석 클리어
    @param    obj  uart 폴객체 포인터
*///----------------------------------------------------------------------------
void  upacket_dle_clear( uart_packet_analysis_t *up )
{
	up->an_seq   = ANSEQ_FIND_STX;
	up->an_cnt   = 0;
	up->dle_flag = 0;
	up->data_cnt = 0;
	up->error    = 0;
}
//------------------------------------------------------------------------------
/** @brief    uart 패켓을 분석하고 패켓이 만들어 지면 콜백함수를 호출한다.
    @param    obj  uart 폴객체 포인터
    @return   사용한 버퍼의 개수
*///----------------------------------------------------------------------------
static int  upacket_dle_analysis( uart_packet_analysis_t *up, char *buf, int count )
{
	char  *wp, uc;
	int    make_packet = 0;

	// 데이타 저장
	void  data_put( uart_packet_analysis_t *up, char data )
	{
		up->data_buf[up->an_cnt++] = data;
	}

	wp = buf;
	while( 0 < count-- )
	{
		uc = *wp++;   
		
		if( up->dle_flag )
		{
			up->dle_flag = 0;
			
			if ( ANSEQ_FIND_STX == up->an_seq )
			{
				if ( up->stx == uc )
				{
					upacket_dle_clear( up );
					up->an_seq = ANSEQ_FIND_ETX;
				}
			}
			else if ( ANSEQ_FIND_ETX == up->an_seq )
			{
				if ( up->etx == uc )
				{
					make_packet = 1;
					break;
				}
				else
				{
					data_put( up, uc );	
				}
			}
		} 
		else
		{
			if ( uc == up->dle )
			{
				up->dle_flag = 1;	
			}
			else
			{
				if ( up->an_seq == ANSEQ_FIND_ETX )
				{
					data_put( up, uc );	
				}
			}
		}
	}
	
	if ( make_packet )
	{
		if ( up->make_crc16 ) 
		{
			unsigned short crc_calc, crc_recv;

			up->an_cnt -= 2;  // crc 제거
			
			crc_recv = up->data_buf[up->an_cnt]<<8 | up->data_buf[up->an_cnt+1];
			crc_calc = up->make_crc16( up->data_buf, up->an_cnt );
			
			if ( crc_recv != crc_calc ) 
			{
				printf( " calc=%04x  recv=%04x\n", crc_calc, crc_recv );
				up->error = ANERR_CRC;
			}
		}
		
		if ( up->on_packet )
		{
			up->on_packet( up->obj, up->data_buf, up->an_cnt, up->error );
		}
		
		upacket_dle_clear( up );
	}
	
	return  wp - buf;
}
//------------------------------------------------------------------------------
/** @brief    uart 에서 데이타를 읽어 패켓을 분석한 후 패켓이 만들어지면
              등록된 콜백함수를 호출한다.
    @param    obj  폴객체 포인터
    @param    callback  패켓이 만들어졌을대 호출되는 함수, NULL 이면 기존 콜백함수가 유지된다.
    @return   받은 데이타 개수
*///----------------------------------------------------------------------------
int  upacket_dle_read_from_uart( poll_obj_t *obj, on_uart_packet_t callback )
{
	uart_packet_analysis_t  *up;
	on_uart_packet_t         save_cb;
	char   buf[UART_PACKET_MAX_SIZE], *wp;
	int    rdcnt, count, checkout;
	
	rdcnt  = uart_read( obj, buf, sizeof(buf) );
	count  = rdcnt;

	up = (uart_packet_analysis_t *)obj->user;

	// 콜백함수 등록
	save_cb = up->on_packet;
	if ( callback ) 
	{
		up->on_packet = callback;
	}

	// 패켓 분석
	wp = buf;
	while( 0 < count )
	{
		checkout = upacket_dle_analysis( up, wp, count );
		wp    += checkout;
		count -= checkout;
		
	}

	// 콜백함수 복귀
	up->on_packet = save_cb;

	return rdcnt;
}
//------------------------------------------------------------------------------
/** @brief    uart 패켓을 분석하고 패켓이 만들어 지면 콜백함수를 호출한다.
    @param    up    upacket 관리 구조체
    @param    snd_buf   실제 전송될 버퍼, 이곳에 데이타가 만들어진다.
    @param    src_buf   데이타 버퍼
    @param    src_cnt   데이타 버퍼의 개수
    @return   만들어진 버퍼의 개수
*///----------------------------------------------------------------------------
static int  upacket_dle_make_packet( uart_packet_analysis_t *up, char *snd_buf, char *src_buf, int src_cnt )
{
	char  *dst, *src;
	int    loop, count;

    // crc
	if ( up->make_crc16 ) 
	{
		unsigned short crc_calc;
		
		crc_calc = up->make_crc16( src_buf, src_cnt );
		src_buf[src_cnt  ] = crc_calc >> 8;
		src_buf[src_cnt+1] = crc_calc & 0xff;
		src_cnt += 2;
	}    
	
	dst = snd_buf;
	src = src_buf;
	
	// STX
	*dst++ = up->dle;
	*dst++ = up->stx;
	
	// DATA(crc)
	for( loop=0; loop<src_cnt; loop++ )
	{
		if ( *src == up->dle )
		{
			*dst++ = up->dle;
		}
		
		*dst++ = *src++;
	}
	
	// ETX
	*dst++ = up->dle;
	*dst++ = up->etx;

	count = dst - snd_buf;
	
	return count;
}
//------------------------------------------------------------------------------
/** @brief    uart 에 패켓을 만들어 전송한다.
    @param    obj  폴객체 포인터
    @param    data_buf   전송할 데이타 버퍼
    @param    count      전송할 데이타 버퍼의 개수
    @return   전송한 데이타 개수
*///----------------------------------------------------------------------------
int  upacket_dle_write_to_uart( poll_obj_t *obj, const char *data_buf, int count  )
{
	uart_packet_analysis_t  *up;
	char   snd_buf[UART_PACKET_MAX_SIZE*2];
	char   src_buf[UART_PACKET_MAX_SIZE  ];
	int    txcnt;

	up = (uart_packet_analysis_t *)obj->user;
	memcpy( src_buf, data_buf, count );

	txcnt = upacket_dle_make_packet( up, snd_buf, src_buf, count );
	txcnt = uart_write( obj, snd_buf, txcnt );

	if (0)
	{
		char str[4096];
		bin_to_hex( str, snd_buf, txcnt );
		printf( "* send=%d\n", txcnt );
		printf( "%s\n", str );
	}

	return txcnt;
}