/** @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 #include #include #include #include #include #include #include #include #include #include #include #include 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; loopdle ) { *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; }