/* $Id: tpam_crcpc.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver - CRC encoding) * * Copyright 1998-2000 AUVERTECH Télécom * Copyright 2001 Stelian Pop , Alcôve * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * For all support questions please contact: * */ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Module Name: crcpc.c Abstract: Modem HDLC coding Software HDLC coding / decoding Revision History: ---------------------------------------------------------------------------*/ #include #include "tpam.h" #define HDLC_CTRL_CHAR_CMPL_MASK 0x20 /* HDLC control character complement mask */ #define HDLC_FLAG 0x7E /* HDLC flag */ #define HDLC_CTRL_ESC 0x7D /* HDLC control escapr character */ #define HDLC_LIKE_FCS_INIT_VAL 0xFFFF /* FCS initial value (0xFFFF for new equipment or 0) */ #define HDLC_FCS_OK 0xF0B8 /* This value is the only valid value of FCS */ #define TRUE 1 #define FALSE 0 static u8 ap_t_ctrl_char_complemented[256]; /* list of characters to complement */ static void ap_hdlc_like_ctrl_char_list (u32 ctrl_char) { int i; for (i = 0; i < 256; ++i) ap_t_ctrl_char_complemented[i] = FALSE; for (i = 0; i < 32; ++i) if ((ctrl_char >> i) & 0x0001) ap_t_ctrl_char_complemented [i] = TRUE; ap_t_ctrl_char_complemented[HDLC_FLAG] = TRUE; ap_t_ctrl_char_complemented[HDLC_CTRL_ESC] = TRUE; } void init_CRC(void) { ap_hdlc_like_ctrl_char_list(0xffffffff); } void hdlc_encode_modem(u8 *buffer_in, u32 lng_in, u8 *buffer_out, u32 *lng_out) { u16 fcs; register u8 data; register u8 *p_data_out = buffer_out; fcs = HDLC_LIKE_FCS_INIT_VAL; /* * Insert HDLC flag at the beginning of the frame */ *p_data_out++ = HDLC_FLAG; #define ESCAPE_CHAR(data_out, data) \ if (ap_t_ctrl_char_complemented[data]) { \ *data_out++ = HDLC_CTRL_ESC; \ *data_out++ = data ^ 0x20; \ } \ else \ *data_out++ = data; while (lng_in--) { data = *buffer_in++; /* * FCS calculation */ fcs = crc_ccitt_byte(fcs, data); ESCAPE_CHAR(p_data_out, data); } /* * Add FCS and closing flag */ fcs ^= 0xFFFF; // Complement data = (u8)(fcs & 0xff); /* LSB */ ESCAPE_CHAR(p_data_out, data); data = (u8)((fcs >> 8)); /* MSB */ ESCAPE_CHAR(p_data_out, data); #undef ESCAPE_CHAR *p_data_out++ = HDLC_FLAG; *lng_out = (u32)(p_data_out - buffer_out); } void hdlc_no_accm_encode(u8 *buffer_in, u32 lng_in, u8 *buffer_out, u32 *lng_out) { u16 fcs; register u8 data; register u8 *p_data_out = buffer_out; /* * Insert HDLC flag at the beginning of the frame */ fcs = HDLC_LIKE_FCS_INIT_VAL; while (lng_in--) { data = *buffer_in++; /* calculate FCS */ fcs = crc_ccitt_byte(fcs, data); *p_data_out++ = data; } /* * Add FCS and closing flag */ fcs ^= 0xFFFF; // Complement data = (u8)(fcs); *p_data_out++ = data; data =(u8)((fcs >> 8)); // revense MSB / LSB *p_data_out++ = data; *lng_out = (u32)(p_data_out - buffer_out); } u32 hdlc_no_accm_decode(u8 *buffer_in, u32 lng_in) { u16 fcs; u32 lng = lng_in; register u8 data; /* * Insert HDLC flag at the beginning of the frame */ fcs = HDLC_LIKE_FCS_INIT_VAL; while (lng_in--) { data = *buffer_in++; /* calculate FCS */ fcs = crc_ccitt_byte(fcs, data); } if (fcs == HDLC_FCS_OK) return (lng-2); else return 0; }