unsigned short UpdateCRC(unsigned short crcIn, unsigned char const* pBuffer, unsigned int len) { unsigned short crcOut = crcIn; for(unsigned int i=0; i < len; ++i, ++pBuffer) { crcOut = update_crc_ccitt(crcOut, *pBuffer); } return crcOut; }
void main( int argc, char *argv[] ) { char input_string[MAX_STRING_SIZE]; char *ptr, *dest, hex_val, prev_byte; unsigned short crc_16, crc_16_modbus, crc_ccitt_ffff, crc_ccitt_0000, crc_ccitt_1d0f, crc_dnp, crc_sick, low_byte, high_byte; unsigned long crc_32; int a, ch, do_ascii, do_hex; FILE *fp; do_ascii = FALSE; do_hex = FALSE; printf( "\nCRC algorithm sample program\nLammert Bies, Version " CRC_VERSION "\n\n" ); if ( argc < 2 ) { printf( "Usage: tst_crc [-a|-x] file1 ...\n\n" ); printf( " -a Program asks for ASCII input. Following parameters ignored.\n" ); printf( " -x Program asks for hexadecimal input. Following parameters ignored.\n" ); printf( " All other parameters are treated like filenames. The CRC values\n" ); printf( " for each separate file will be calculated.\n" ); exit( 0 ); } if ( ! strcmp( argv[1], "-a" ) || ! strcmp( argv[1], "-A" ) ) do_ascii = TRUE; if ( ! strcmp( argv[1], "-x" ) || ! strcmp( argv[1], "-X" ) ) do_hex = TRUE; if ( do_ascii || do_hex ) { printf( "Input: " ); fgets( input_string, MAX_STRING_SIZE-1, stdin ); } if ( do_ascii ) { ptr = input_string; while ( *ptr && *ptr != '\r' && *ptr != '\n' ) ptr++; *ptr = 0; } if ( do_hex ) { ptr = input_string; dest = input_string; while( *ptr && *ptr != '\r' && *ptr != '\n' ) { if ( *ptr >= '0' && *ptr <= '9' ) *dest++ = (char) ( (*ptr) - '0' ); if ( *ptr >= 'A' && *ptr <= 'F' ) *dest++ = (char) ( (*ptr) - 'A' + 10 ); if ( *ptr >= 'a' && *ptr <= 'f' ) *dest++ = (char) ( (*ptr) - 'a' + 10 ); ptr++; } * dest = '\x80'; *(dest+1) = '\x80'; } a = 1; do { crc_16 = 0; crc_16_modbus = 0xffff; crc_dnp = 0; crc_sick = 0; crc_ccitt_0000 = 0; crc_ccitt_ffff = 0xffff; crc_ccitt_1d0f = 0x1d0f; crc_32 = 0xffffffffL; if ( do_ascii ) { prev_byte = 0; ptr = input_string; while ( *ptr ) { crc_16 = update_crc_16( crc_16, *ptr ); crc_16_modbus = update_crc_16( crc_16_modbus, *ptr ); crc_dnp = update_crc_dnp( crc_dnp, *ptr ); crc_sick = update_crc_sick( crc_sick, *ptr, prev_byte ); crc_ccitt_0000 = update_crc_ccitt( crc_ccitt_0000, *ptr ); crc_ccitt_ffff = update_crc_ccitt( crc_ccitt_ffff, *ptr ); crc_ccitt_1d0f = update_crc_ccitt( crc_ccitt_1d0f, *ptr ); crc_32 = update_crc_32( crc_32, *ptr ); prev_byte = *ptr; ptr++; } } else if ( do_hex ) { prev_byte = 0; ptr = input_string; while ( *ptr != '\x80' ) { hex_val = (char) ( ( * ptr & '\x0f' ) << 4 ); hex_val |= (char) ( ( *(ptr+1) & '\x0f' ) ); crc_16 = update_crc_16( crc_16, hex_val ); crc_16_modbus = update_crc_16( crc_16_modbus, hex_val ); crc_dnp = update_crc_dnp( crc_dnp, hex_val ); crc_sick = update_crc_sick( crc_sick, hex_val, prev_byte ); crc_ccitt_0000 = update_crc_ccitt( crc_ccitt_0000, hex_val ); crc_ccitt_ffff = update_crc_ccitt( crc_ccitt_ffff, hex_val ); crc_ccitt_1d0f = update_crc_ccitt( crc_ccitt_1d0f, hex_val ); crc_32 = update_crc_32( crc_32, hex_val ); prev_byte = hex_val; ptr += 2; } input_string[0] = 0; } else { prev_byte = 0; fp = fopen( argv[a], "rb" ); if ( fp != NULL ) { while( ( ch=fgetc( fp ) ) != EOF ) { crc_16 = update_crc_16( crc_16, (char) ch ); crc_16_modbus = update_crc_16( crc_16_modbus, (char) ch ); crc_dnp = update_crc_dnp( crc_dnp, (char) ch ); crc_sick = update_crc_sick( crc_sick, (char) ch, prev_byte ); crc_ccitt_0000 = update_crc_ccitt( crc_ccitt_0000, (char) ch ); crc_ccitt_ffff = update_crc_ccitt( crc_ccitt_ffff, (char) ch ); crc_ccitt_1d0f = update_crc_ccitt( crc_ccitt_1d0f, (char) ch ); crc_32 = update_crc_32( crc_32, (char) ch ); prev_byte = (char) ch; } fclose( fp ); } else printf( "%s : cannot open file\n", argv[a] ); } crc_32 ^= 0xffffffffL; crc_dnp = ~crc_dnp; low_byte = (crc_dnp & 0xff00) >> 8; high_byte = (crc_dnp & 0x00ff) << 8; crc_dnp = low_byte | high_byte; low_byte = (crc_sick & 0xff00) >> 8; high_byte = (crc_sick & 0x00ff) << 8; crc_sick = low_byte | high_byte; printf( "%s%s%s :\nCRC16 = 0x%04X / %u\n" "CRC16 (Modbus) = 0x%04X / %u\n" "CRC16 (Sick) = 0x%04X / %u\n" "CRC-CCITT (0x0000) = 0x%04X / %u\n" "CRC-CCITT (0xffff) = 0x%04X / %u\n" "CRC-CCITT (0x1d0f) = 0x%04X / %u\n" "CRC-DNP = 0x%04X / %u\n" "CRC32 = 0x%08lX / %lu\n" , ( do_ascii || do_hex ) ? "\"" : "" , ( ! do_ascii && ! do_hex ) ? argv[a] : input_string , ( do_ascii || do_hex ) ? "\"" : "" , crc_16, crc_16 , crc_16_modbus, crc_16_modbus , crc_sick, crc_sick , crc_ccitt_0000, crc_ccitt_0000 , crc_ccitt_ffff, crc_ccitt_ffff , crc_ccitt_1d0f, crc_ccitt_1d0f , crc_dnp, crc_dnp , crc_32, crc_32 ); a++; } while ( a < argc ); } /* main (tst_crc.c) */
/* Subroutine: bit_slicer() * Description: recover bits from the channel * Input: * channel: up to 2 channels are supported for now * amplitude: sample value * Output: none */ forceinline void bit_slicer(const uint8_t channel, const int32_t amplitude) { /* Why is everything so "static"? As mentioned in the "forceinline" * comment way above, these subroutines are not real subroutines. Thus we * need to use "static" in order to preserve the buffer contents. Or use * global variables. * The best part is why the 'packet' buffer is also "static": nRF905 * resends the packets (sometimes on different channels). If we miss some * bits on the first try, perhaps we manage to get them on the second * attempt. Note that this is only possible because we differentiate * "0" from "1" from "missing" during the decoding step! */ static int32_t cb_buf_pcm[2][smooth_buffer_size]; static uint16_t cb_idx_pcm[2]; static uint8_t cb_buf_bit[2][buffer_size]; static uint16_t cb_idx_bit[2]; static int32_t sliding_sum[2]; static uint16_t skip_samples[2]; static uint8_t packet[max_packet_bytes]; uint16_t i, j, k; uint16_t bad_manchester; uint16_t crc16 = 0xffff; /* Simplest possible noise filter (at least, in software): sliding average. */ cb_write(pcm[channel], amplitude); sliding_sum[channel] -= cb_readn(pcm[channel], average_n); sliding_sum[channel] += amplitude; /* Input for bit_slicer() is the magnitude at the space pulse frequency minus * the magnitude at the mark pulse frequency. If this value is positive, * the space signal is stronger than the mark signal. Thus, by convention, * we have the "0" symbol. Same thing happens for the "1" symbol. * However, these symbols are not bits yet: actual bits are encoded using * the Manchester coding. */ cb_write(bit[channel], sliding_sum[channel] > 0 ? 1 : 0); /* Don't reprocess samples if we already decoded this as a valid message. * This saves a lot of processing time, specially when dealing with busy * channels. */ if (skip_samples[channel]) { skip_samples[channel]--; return; } /* Attempt to match the preamble bit pattern. Bail out on the first * discrepancy to spare CPU cycles. This is the hottest code path * (most CPU-intensive). */ for ( i = packet_samples, j = 0; j < preamble_bits; i -= symbol_samples, j++ ) { if (preamble_pattern[j] != cb_readn(bit[channel], i)) return; } /* When the preamble looks like valid, attempt to decode the rest of the * packet. All the bits (including the preamble) are Manchester-coded. * This means that the symbol values do not matter, only symbol transitions * do encode the actual bits. For instance, "01" means "1", while "10" means * "0". Both "00" and "11" are invalid, when one of these is detected, the * bit is skipped (and the bit from the previous decoding attempt for this * position is used). If there are too many invalid bits, probably the * thing interpreted as preamble was a fluctuation in randomness, so we * bail out. And yes, preamble is also Manchester-coded, in case you're * wondering. nRF905 preamble is usually stated as having 10 bits. But * Manchester-coded nRF905 preamble has 20 bits. */ bad_manchester = 0; for ( i = packet_samples - preamble_bits * symbol_samples, j = 0; i > symbol_samples; i -= symbol_samples * 2, j++ ) { k = j / 8; if (cb_readn(bit[channel], i) != cb_readn(bit[channel], i + symbol_samples)) { // valid Manchester if (cb_readn(bit[channel], i)) { // set to 1 packet[k] |= (1 << (7 - (j & 7))); } else { // set to 0 packet[k] &= ~(1 << (7 - (j & 7))); } } else { // heuristic, skip if too many bit encoding errors if (++bad_manchester > j / 2) return; } /* At the end of every 8-bit chunk, update CRC checksum. When the * checksum is (looks like) correct, proceed and output the packet * bytes, regardless the packet size. It is quite possible that some * incompletely processed packet appears to have a correct CRC. * If the desired packet size is known/fixed and/or CRC is unavailable, * it is possible to use packet size as the "packet received" condition. */ if ((j & 7) == 7) { crc16 = use_crc ? update_crc_ccitt(crc16, packet[k]) : 0; k++; if (crc16 == 0 && k == (packet_bytes ? packet_bytes : k)) { output((const uint8_t *) packet, k, channel); skip_samples[channel] = symbol_samples * 2 * (preamble_bits + k * 8); /* memset((void *) packet, 0, sizeof(packet)); */ return; } } } }
void create_dls_datagroup (char* text, int padlen, UCHAR*** p_dlsdg, int* p_numdg) { UCHAR dlsseg[8][16]; // max 8 segments, each max 16 chars UCHAR** dlsdg; // Array of datagroups composing dls text; int numseg; // Number of DSL segments int lastseglen; // Length of the last segment int numdg; // Number of data group int xpadlengthmask; int i, j, k, z, idx_start_crc, idx_stop_crc; USHORT dlscrc; static UCHAR toggle = 0; if (toggle == 0) toggle = 1; else toggle = 0; numseg = strlen(text) / 16; lastseglen = strlen(text) % 16; if (padlen-9 >= 16) { if (lastseglen > 0) { numseg++; // The last incomplete segment } // The PAD can contain the full segmnet and overhead (9 bytes) numdg = numseg; } else { // Each 16 char segment span over 2 dg numdg = numseg * 2; if (lastseglen > 0) { numseg++; // The last incomplete segment if (lastseglen <= padlen-9) { numdg += 1; } else { numdg += 2; } } } *p_numdg = numdg; fprintf(stderr, "PAD Length: %d\n", padlen); fprintf(stderr, "DLS text: %s\n", text); fprintf(stderr, "Number of DLS segments: %d\n", numseg); fprintf(stderr, "Number of DLS data groups: %d\n", numdg); xpadlengthmask = get_xpadlengthmask(padlen); *p_dlsdg = (UCHAR**) malloc(numdg * sizeof(UCHAR*)); dlsdg = *p_dlsdg; i = 0; for (z=0; z < numseg; z++) { char* curseg; int curseglen; UCHAR firstseg, lastseg; curseg = &text[z * 16]; fprintf(stderr, "Segment number %d\n", z+1); if (z == 0) { // First segment firstseg = 1; } else { firstseg = 0; } if (z == numseg-1) { //Last segment if (lastseglen != 0) { curseglen = lastseglen; } else { curseglen = 16; } lastseg = 1; } else { curseglen = 16; lastseg = 0; } if (curseglen <= padlen-9) { // Segment is composed of 1 data group dlsdg[i] = (UCHAR*) malloc(padlen * sizeof(UCHAR)); // FF-PAD Byte L (CI=1) dlsdg[i][padlen-1]=0x02; // FF-PAD Byte L-1 (Variable size X_PAD) dlsdg[i][padlen-2]=0x20; // CI => data length = 12 (011) - Application Type=2 // (DLS - start of X-PAD data group) dlsdg[i][padlen-3]=(xpadlengthmask<<5) | 0x02; // End of CI list dlsdg[i][padlen-4]=0x00; // DLS Prefix (T=1,Only one segment,segment length-1) dlsdg[i][padlen-5]=((toggle*8+firstseg*4+lastseg*2+0)<<4) | (curseglen-1); if (firstseg==1) { // DLS Prefix (Charset standard) dlsdg[i][padlen-6]=0x00; } else { // DLS SegNum dlsdg[i][padlen-6]=z<<4; } // CRC start from prefix idx_start_crc = padlen-5; // DLS text for (j = 0; j < curseglen; j++) { dlsdg[i][padlen-7-j] = curseg[j]; } idx_stop_crc = padlen - 7 - curseglen+1; dlscrc = 0xffff; for (j = idx_start_crc; j >= idx_stop_crc; j--) { dlscrc = update_crc_ccitt(dlscrc, dlsdg[i][j]); } dlscrc = ~dlscrc; fprintf(stderr, "crc=%x ~crc=%x\n", ~dlscrc, dlscrc); dlsdg[i][padlen-7-curseglen] = (dlscrc & 0xFF00) >> 8; // HI CRC dlsdg[i][padlen-7-curseglen-1] = dlscrc & 0x00FF; // LO CRC // NULL PADDING for (j = padlen-7-curseglen-2; j >= 0; j--) { dlsdg[i][j]=0x00; } fprintf(stderr, "Data group: "); for (j = 0; j < padlen; j++) fprintf(stderr, "%x ", dlsdg[i][j]); fprintf(stderr, "\n"); i++; } else { // Segment is composed of 2 data groups