diff --git a/libs/freetdm/Makefile b/libs/freetdm/Makefile index a8296a3334..17661180d7 100644 --- a/libs/freetdm/Makefile +++ b/libs/freetdm/Makefile @@ -113,7 +113,7 @@ testapp: $(SRC)/testapp.c $(MYLIB) $(CC) $(INCS) -L. $(SRC)/testapp.c -o testapp -lopenzap -lm -lpthread testcid: $(SRC)/testcid.c $(MYLIB) - $(CC) $(INCS) -L. $(SRC)/testcid.c -o testcid -lopenzap -lm -lpthread + $(CC) $(INCS) -L. -g -ggdb $(SRC)/testcid.c -o testcid -lopenzap -lm -lpthread testtones: $(SRC)/testtones.c $(MYLIB) $(CC) $(INCS) -L. $(SRC)/testtones.c -o testtones -lopenzap -lm -lpthread diff --git a/libs/freetdm/src/fsk.c b/libs/freetdm/src/fsk.c index 69b2edfc88..d933166227 100644 --- a/libs/freetdm/src/fsk.c +++ b/libs/freetdm/src/fsk.c @@ -46,7 +46,7 @@ #define M_PI 3.14159265358979323846 #endif -static fsk_modem_definition_t fsk_modem_definitions[] = +fsk_modem_definition_t fsk_modem_definitions[] = { { /* FSK_V23_FORWARD_MODE1 */ 1700, 1300, 600 }, { /* FSK_V23_FORWARD_MODE2 */ 2100, 1300, 1200 }, diff --git a/libs/freetdm/src/include/fsk.h b/libs/freetdm/src/include/fsk.h index e6ca995d57..b098444d03 100644 --- a/libs/freetdm/src/include/fsk.h +++ b/libs/freetdm/src/include/fsk.h @@ -107,5 +107,7 @@ void dsp_fsk_destroy(dsp_fsk_handle_t **handle); void dsp_fsk_sample(dsp_fsk_handle_t *handle, double normalized_sample); +extern fsk_modem_definition_t fsk_modem_definitions[]; + #endif diff --git a/libs/freetdm/src/include/libteletone_generate.h b/libs/freetdm/src/include/libteletone_generate.h index 177c893966..de6697bb29 100644 --- a/libs/freetdm/src/include/libteletone_generate.h +++ b/libs/freetdm/src/include/libteletone_generate.h @@ -156,7 +156,6 @@ static __inline__ int16_t teletone_dds_state_modulate_sample(teletone_dds_state_ } dds->phase_accumulator += dds->phase_rate[pindex]; - return (int16_t) (sample * dds->scale_factor >> 15); } diff --git a/libs/freetdm/src/include/openzap.h b/libs/freetdm/src/include/openzap.h index e1dc74c649..0e7887bd20 100644 --- a/libs/freetdm/src/include/openzap.h +++ b/libs/freetdm/src/include/openzap.h @@ -241,6 +241,46 @@ static __inline__ char *zap_clean_string(char *s) return s; } +struct zap_bitstream { + uint8_t *data; + uint32_t datalen; + uint32_t byte_index; + uint8_t bit_index; + int8_t endian; + uint8_t top; + uint8_t bot; + uint8_t ss; + uint8_t ssv; +}; + +struct zap_fsk_data_state { + dsp_fsk_handle_t *fsk1200_handle; + uint8_t init; + uint8_t *buf; + size_t bufsize; + zap_size_t blen; + zap_size_t bpos; + zap_size_t dlen; + zap_size_t ppos; + int checksum; +}; + +struct zap_fsk_modulator { + teletone_dds_state_t dds; + zap_bitstream_t bs; + uint32_t carrier_bits_start; + uint32_t carrier_bits_stop; + uint32_t chan_sieze_bits; + uint32_t bit_factor; + uint32_t bit_accum; + uint32_t sample_counter; + fsk_modem_types_t modem_type; + zap_fsk_data_state_t *fsk_data; + zap_fsk_write_sample_t write_sample_callback; + void *user_data; + int16_t sample_buffer[64]; +}; + struct zap_caller_data { char cid_name[80]; char cid_num[80]; @@ -364,11 +404,31 @@ struct zap_io_interface { zio_span_next_event_t next_event; }; +#define zap_fsk_modulator_send_all(_it) zap_fsk_modulator_generate_chan_sieze(_it); \ + zap_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_start); \ + zap_fsk_modulator_send_data(_it); \ + zap_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_stop) + +zap_status_t zap_fsk_modulator_init(zap_fsk_modulator_t *fsk_trans, + fsk_modem_types_t modem_type, + uint32_t sample_rate, + zap_fsk_data_state_t *fsk_data, + float db_level, + uint32_t carrier_bits_start, + uint32_t carrier_bits_stop, + uint32_t chan_sieze_bits, + zap_fsk_write_sample_t write_sample_callback, + void *user_data); +int8_t zap_bitstream_get_bit(zap_bitstream_t *bsp); +void zap_bitstream_init(zap_bitstream_t *bsp, uint8_t *data, uint32_t datalen, zap_endian_t endian, int ss); zap_status_t zap_fsk_data_parse(zap_fsk_data_state_t *state, zap_size_t *type, char **data, zap_size_t *len); zap_status_t zap_fsk_demod_feed(zap_fsk_data_state_t *state, int16_t *data, size_t samples); zap_status_t zap_fsk_demod_destroy(zap_fsk_data_state_t *state); int zap_fsk_demod_init(zap_fsk_data_state_t *state, int rate, uint8_t *buf, size_t bufsize); - +zap_status_t zap_fsk_data_init(zap_fsk_data_state_t *state, uint8_t *data, uint32_t datalen); +zap_status_t zap_fsk_data_add_mdmf(zap_fsk_data_state_t *state, zap_mdmf_type_t type, int8_t *data, uint32_t datalen); +zap_status_t zap_fsk_data_add_checksum(zap_fsk_data_state_t *state); +zap_status_t zap_fsk_data_add_sdmf(zap_fsk_data_state_t *state, char *date, char *number); zap_status_t zap_channel_outgoing_call(zap_channel_t *zchan); void zap_channel_rotate_tokens(zap_channel_t *zchan); void zap_channel_clear_detected_tones(zap_channel_t *zchan); @@ -403,7 +463,7 @@ zap_status_t zap_global_destroy(void); void zap_global_set_logger(zap_logger_t logger); void zap_global_set_default_logger(int level); uint32_t zap_separate_string(char *buf, char delim, char **array, int arraylen); -void print_bits(uint8_t *b, int bl, char *buf, int blen, int e); +void print_bits(uint8_t *b, int bl, char *buf, int blen, int e, int ss); ZIO_CODEC_FUNCTION(zio_slin2ulaw); ZIO_CODEC_FUNCTION(zio_ulaw2slin); ZIO_CODEC_FUNCTION(zio_slin2alaw); diff --git a/libs/freetdm/src/include/zap_types.h b/libs/freetdm/src/include/zap_types.h index 84f74ee556..2ae6e7b05d 100644 --- a/libs/freetdm/src/include/zap_types.h +++ b/libs/freetdm/src/include/zap_types.h @@ -60,9 +60,15 @@ struct zap_io_interface; #define ZAP_COMMAND_OBJ_INT *((int *)obj) #define ZAP_COMMAND_OBJ_CHAR_P (char *)obj +#define ZAP_FSK_MOD_FACTOR 0x10000 typedef uint64_t zap_time_t; +typedef enum { + ZAP_ENDIAN_BIG = 1, + ZAP_ENDIAN_LITTLE = -1 +} zap_endian_t; + typedef enum { ZAP_CID_TYPE_SDMF = 0x04, ZAP_CID_TYPE_MDMF = 0x80 @@ -75,28 +81,12 @@ typedef enum { MDMF_NO_NUM = 4, MDMF_PHONE_NAME = 7, MDMF_NO_NAME = 8, - MDMF_INVALID = 9 + MDMF_ALT_ROUTE = 9, + MDMF_INVALID = 10 } zap_mdmf_type_t; -#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "INVALID" +#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID" ZAP_STR2ENUM_P(zap_str2zap_mdmf_type, zap_mdmf_type2str, zap_mdmf_type_t) -struct zap_fsk_data_state { - dsp_fsk_handle_t *fsk1200_handle; - uint8_t init; - uint8_t *buf; - size_t bufsize; - zap_size_t blen; - zap_size_t bpos; - zap_size_t dlen; - zap_size_t ppos; - int checksum; -}; -typedef struct zap_fsk_data_state zap_fsk_data_state_t; - -typedef int (*zap_fsk_data_decoder_t)(zap_fsk_data_state_t *state); - - - #define ZAP_TONEMAP_LEN 128 typedef enum { ZAP_TONEMAP_NONE, @@ -364,13 +354,18 @@ typedef zap_status_t (*zio_write_t) ZIO_WRITE_ARGS ; #define ZAP_LOG_ALERT ZAP_PRE, ZAP_LOG_LEVEL_ALERT #define ZAP_LOG_EMERG ZAP_PRE, ZAP_LOG_LEVEL_EMERG - +typedef struct zap_fsk_data_state zap_fsk_data_state_t; +typedef int (*zap_fsk_data_decoder_t)(zap_fsk_data_state_t *state); +typedef zap_status_t (*zap_fsk_write_sample_t)(int16_t *buf, zap_size_t buflen, void *user_data); typedef void (*zap_logger_t)(char *file, const char *func, int line, int level, char *fmt, ...); typedef struct zap_io_interface zap_io_interface_t; typedef struct hashtable zap_hash_t; typedef struct hashtable_itr zap_hash_itr_t; typedef struct key zap_hash_key_t; typedef struct value zap_hash_val_t; +typedef struct zap_bitstream zap_bitstream_t; +typedef struct zap_fsk_modulator zap_fsk_modulator_t; + #endif /* For Emacs: diff --git a/libs/freetdm/src/testcid.c b/libs/freetdm/src/testcid.c index 545794689c..a75dee81de 100644 --- a/libs/freetdm/src/testcid.c +++ b/libs/freetdm/src/testcid.c @@ -1,17 +1,73 @@ #include "openzap.h" +struct helper { + int fd; +}; + +zap_status_t my_write_sample(int16_t *buf, zap_size_t buflen, void *user_data) +{ + int x ; + + struct helper *foo = (struct helper *) user_data; + for (x = 0; x < buflen; x++) { + printf("%x ", buf[x]); + } + printf("\n"); + write(foo->fd, buf, buflen * 2); +} + int main(int argc, char *argv[]) { - zap_fsk_data_state_t state = {0}; - int fd; + struct zap_fsk_modulator fsk_trans; + zap_fsk_data_state_t fsk_data = {0}; + int fd = -1; int16_t buf[160] = {0}; ssize_t len = 0; int type, mlen; char *sp; char str[128] = ""; char fbuf[256]; + uint8_t databuf[1024] = ""; + struct helper foo; + + + + if (argc < 2) { + int x; + char *url = "sip:cool@rad.com"; - if (argc < 2 || zap_fsk_demod_init(&state, 8000, fbuf, sizeof(fbuf))) { + if ((fd = open("tone.raw", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { + fprintf(stderr, "File Error!\n", strerror(errno)); + exit(-1); + } + + + zap_fsk_data_init(&fsk_data, databuf, sizeof(databuf)); +#if 1 + zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, "06061234", 8); + zap_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NUM, "5551212", 7); + zap_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NAME, "Fred Smith", 10); + //zap_fsk_data_add_mdmf(&fsk_data, MDMF_ALT_ROUTE, url, strlen(url)); +#else + zap_fsk_data_add_sdmf(&fsk_data, "06061234", "0"); + //zap_fsk_data_add_sdmf(&state, "06061234", "5551212"); +#endif + zap_fsk_data_add_checksum(&fsk_data); + + foo.fd = fd; + + + zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, 8000, &fsk_data, -14, 180, 5, 300, my_write_sample, &foo); + zap_fsk_modulator_send_all((&fsk_trans)); + + if (fd > -1) { + close (fd); + } + + return 0; + } + + if (zap_fsk_demod_init(&fsk_data, 8000, fbuf, sizeof(fbuf))) { printf("wtf\n"); return 0; } @@ -22,19 +78,19 @@ int main(int argc, char *argv[]) } while((len = read(fd, buf, sizeof(buf))) > 0) { - if (zap_fsk_demod_feed(&state, buf, len / 2) != ZAP_SUCCESS) { + if (zap_fsk_demod_feed(&fsk_data, buf, len / 2) != ZAP_SUCCESS) { break; } } - while(zap_fsk_data_parse(&state, &type, &sp, &mlen) == ZAP_SUCCESS) { + while(zap_fsk_data_parse(&fsk_data, &type, &sp, &mlen) == ZAP_SUCCESS) { zap_copy_string(str, sp, mlen+1); *(str+mlen) = '\0'; zap_clean_string(str); printf("TYPE %d (%s) LEN %d VAL [%s]\n", type, zap_mdmf_type2str(type), mlen, str); } - zap_fsk_demod_destroy(&state); + zap_fsk_demod_destroy(&fsk_data); close(fd); } diff --git a/libs/freetdm/src/zap_callerid.c b/libs/freetdm/src/zap_callerid.c index f3a685f55a..7b41117670 100644 --- a/libs/freetdm/src/zap_callerid.c +++ b/libs/freetdm/src/zap_callerid.c @@ -3,6 +3,7 @@ #include "uart.h" + static void fsk_byte_handler (void *x, int data) { zap_fsk_data_state_t *state = (zap_fsk_data_state_t *) x; @@ -36,6 +37,62 @@ static void fsk_byte_handler (void *x, int data) } } +zap_status_t zap_fsk_data_init(zap_fsk_data_state_t *state, uint8_t *data, uint32_t datalen) +{ + memset(state, 0, sizeof(*state)); + state->buf = data; + state->bufsize = datalen; + state->bpos = 2; + + return ZAP_SUCCESS; +} + +zap_status_t zap_fsk_data_add_sdmf(zap_fsk_data_state_t *state, char *date, char *number) +{ + size_t dlen = strlen(date); + size_t nlen = strlen(number); + + state->buf[0] = ZAP_CID_TYPE_SDMF; + memcpy(&state->buf[state->bpos], date, dlen); + state->bpos += dlen; + memcpy(&state->buf[state->bpos], number, nlen); + state->bpos += nlen; + + return ZAP_SUCCESS; +} + +zap_status_t zap_fsk_data_add_mdmf(zap_fsk_data_state_t *state, zap_mdmf_type_t type, int8_t *data, uint32_t datalen) +{ + state->buf[0] = ZAP_CID_TYPE_MDMF; + state->buf[state->bpos++] = type; + state->buf[state->bpos++] = datalen; + memcpy(&state->buf[state->bpos], data, datalen); + state->bpos += datalen; + return ZAP_SUCCESS; +} + + +zap_status_t zap_fsk_data_add_checksum(zap_fsk_data_state_t *state) +{ + uint32_t i; + uint8_t check = 0; + + state->buf[1] = state->bpos - 2; + + for (i = 0; i < state->bpos; i++) { + check += state->buf[i]; + } + + state->checksum = state->buf[state->bpos] = 256 - check; + state->bpos++; + + state->dlen = state->bpos; + state->blen = state->buf[1]; + + return ZAP_SUCCESS; +} + + zap_status_t zap_fsk_data_parse(zap_fsk_data_state_t *state, zap_size_t *type, char **data, zap_size_t *len) { @@ -54,6 +111,7 @@ zap_status_t zap_fsk_data_parse(zap_fsk_data_state_t *state, zap_size_t *type, c } state->checksum = sum % 256; state->ppos = 2; + if (state->buf[0] != ZAP_CID_TYPE_MDMF && state->buf[0] != ZAP_CID_TYPE_SDMF) { state->checksum = -1; } @@ -139,4 +197,101 @@ int zap_fsk_demod_init(zap_fsk_data_state_t *state, int rate, uint8_t *buf, zap_ return ZAP_SUCCESS; } +zap_size_t zap_fsk_modulator_generate_bit(zap_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, zap_size_t buflen) +{ + zap_size_t i; + + for(i = 0 ; i < buflen; i++) { + fsk_trans->bit_accum += fsk_trans->bit_factor; + if (fsk_trans->bit_accum >= ZAP_FSK_MOD_FACTOR) { + fsk_trans->bit_accum -= (ZAP_FSK_MOD_FACTOR + fsk_trans->bit_factor); + break; + } + + buf[i] = teletone_dds_state_modulate_sample(&fsk_trans->dds, bit); + } + + return i; +} + + +int32_t zap_fsk_modulator_generate_carrier_bits(zap_fsk_modulator_t *fsk_trans, uint32_t bits) +{ + uint32_t i = 0; + zap_size_t r = 0; + int bit = 1; + + for (i = 0; i < bits; i++) { + if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) { + fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data); + } else { + break; + } + } + + return i; +} + + +void zap_fsk_modulator_generate_chan_sieze(zap_fsk_modulator_t *fsk_trans) +{ + uint32_t i = 0; + zap_size_t r = 0; + int bit = 0; + + for (i = 0; i < fsk_trans->chan_sieze_bits; i++) { + if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) { + fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data); + } else { + break; + } + bit = !bit; + } + + +} + + +void zap_fsk_modulator_send_data(zap_fsk_modulator_t *fsk_trans) +{ + zap_size_t r = 0; + int8_t bit = 0; + + while((bit = zap_bitstream_get_bit(&fsk_trans->bs)) > -1) { + if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) { + fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data); + } else { + break; + } + } +} + + +zap_status_t zap_fsk_modulator_init(zap_fsk_modulator_t *fsk_trans, + fsk_modem_types_t modem_type, + uint32_t sample_rate, + zap_fsk_data_state_t *fsk_data, + float db_level, + uint32_t carrier_bits_start, + uint32_t carrier_bits_stop, + uint32_t chan_sieze_bits, + zap_fsk_write_sample_t write_sample_callback, + void *user_data) +{ + memset(fsk_trans, 0, sizeof(*fsk_trans)); + fsk_trans->modem_type = modem_type; + teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_space, sample_rate, 0); + teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_mark, sample_rate, 1); + fsk_trans->bit_factor = (fsk_modem_definitions[fsk_trans->modem_type].baud_rate * ZAP_FSK_MOD_FACTOR) / (float)sample_rate; + fsk_trans->bit_accum = 0; + fsk_trans->fsk_data = fsk_data; + teletone_dds_state_set_tx_level(&fsk_trans->dds, db_level); + zap_bitstream_init(&fsk_trans->bs, fsk_trans->fsk_data->buf, fsk_trans->fsk_data->dlen, ZAP_ENDIAN_BIG, 1); + fsk_trans->carrier_bits_start = carrier_bits_start; + fsk_trans->carrier_bits_stop = carrier_bits_stop; + fsk_trans->chan_sieze_bits = chan_sieze_bits; + fsk_trans->write_sample_callback = write_sample_callback; + fsk_trans->user_data = user_data; + return ZAP_SUCCESS; +} diff --git a/libs/freetdm/src/zap_io.c b/libs/freetdm/src/zap_io.c index d4df53f3ce..597979c231 100644 --- a/libs/freetdm/src/zap_io.c +++ b/libs/freetdm/src/zap_io.c @@ -1832,34 +1832,95 @@ uint32_t zap_separate_string(char *buf, char delim, char **array, int arraylen) return argc; } -void print_bits(uint8_t *b, int bl, char *buf, int blen, int e) +void zap_bitstream_init(zap_bitstream_t *bsp, uint8_t *data, uint32_t datalen, zap_endian_t endian, int ss) { - int i,j = 0, k, l = 0; + memset(bsp, 0, sizeof(*bsp)); + bsp->data = data; + bsp->datalen = datalen; + bsp->endian = endian; + bsp->ss = ss; + + if (endian < 0) { + bsp->top = bsp->bit_index = 7; + bsp->bot = 0; + } else { + bsp->top = bsp->bit_index = 0; + bsp->bot = 7; + } + +} + +int8_t zap_bitstream_get_bit(zap_bitstream_t *bsp) +{ + int8_t bit = -1; + + + if (bsp->byte_index >= bsp->datalen) { + goto done; + } + + if (bsp->ss) { + if (!bsp->ssv) { + bsp->ssv = 1; + return 0; + } else if (bsp->ssv == 2) { + bsp->byte_index++; + bsp->ssv = 0; + return 1; + } + } + + + + + bit = (bsp->data[bsp->byte_index] >> (bsp->bit_index)) & 1; + + if (bsp->bit_index == bsp->bot) { + bsp->bit_index = bsp->top; + if (bsp->ss) { + bsp->ssv = 2; + goto done; + } + + if (++bsp->byte_index > bsp->datalen) { + bit = -1; + goto done; + } + + } else { + bsp->bit_index += bsp->endian; + } + + + done: + return bit; +} + + +void print_bits(uint8_t *b, int bl, char *buf, int blen, zap_endian_t e, int ss) +{ + zap_bitstream_t bs; + int j = 0, c = 0; + int8_t bit; + uint32_t last; if (blen < (bl * 10) + 2) { - return; - } - - for (k = 0 ; k < bl; k++) { - buf[j++] = '['; - if (e) { - for(i = 7; i >= 0; i--) { - buf[j++] = ((b[k] & (1 << i)) ? '1' : '0'); - } - } else { - for(i = 0; i < 8; i++) { - buf[j++] = ((b[k] & (1 << i)) ? '1' : '0'); - } - } - buf[j++] = ']'; - buf[j++] = ' '; - if (++l == 6) { - buf[j++] = '\n'; - l = 0; - } - } + return; + } - buf[j++] = '\0'; + zap_bitstream_init(&bs, b, bl, e, ss); + last = bs.byte_index; + while((bit = zap_bitstream_get_bit(&bs)) > -1) { + buf[j++] = bit ? '1' : '0'; + if (bs.byte_index != last) { + buf[j++] = ' '; + last = bs.byte_index; + if (++c == 8) { + buf[j++] = '\n'; + c = 0; + } + } + } } diff --git a/libs/freetdm/src/zap_isdn.c b/libs/freetdm/src/zap_isdn.c index 76ad83ca25..f9577e4798 100644 --- a/libs/freetdm/src/zap_isdn.c +++ b/libs/freetdm/src/zap_isdn.c @@ -89,7 +89,7 @@ static int zap_isdn_921_21(void *pvt, L2UCHAR *msg, L2INT mlen) zap_size_t len = (zap_size_t) mlen; #ifdef IODEBUG char bb[4096] = ""; - print_bits(msg, (int)len, bb, sizeof(bb), 1); + print_bits(msg, (int)len, bb, sizeof(bb), 1, 0); zap_log(ZAP_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)len, LINE, bb); #endif @@ -140,7 +140,7 @@ static void *zap_isdn_run(zap_thread_t *me, void *obj) if (zap_channel_read(data->dchan, buf, &len) == ZAP_SUCCESS) { #ifdef IODEBUG char bb[4096] = ""; - print_bits(buf, (int)len, bb, sizeof(bb), 1); + print_bits(buf, (int)len, bb, sizeof(bb), 1, 0); zap_log(ZAP_LOG_DEBUG, "READ %d\n%s\n%s\n\n", (int)len, LINE, bb); #endif