summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-11-19 19:50:12 +0100
committerPatrick McHardy <kaber@trash.net>2010-11-19 19:50:12 +0100
commita222b17339c75f5bd0aca67033e28ec0586ba206 (patch)
treeef277c6543376fae1b939ff63eae9fe972ba8ca3
parent6629561108d86d26dddbf4a522964c3df80dd95e (diff)
dectmon: add interactive CLI, audio support and more
Not finished yet, but commit is already much too large and includes multiple unrelated things. Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--Makefile.defs.in2
-rw-r--r--configure.ac8
-rw-r--r--include/cli.h37
-rw-r--r--include/dectmon.h30
-rw-r--r--include/utils.h76
-rw-r--r--src/.gitignore3
-rw-r--r--src/Makefile.in8
-rw-r--r--src/audio.c120
-rw-r--r--src/ccitt-adpcm/README94
-rw-r--r--src/ccitt-adpcm/decode.c113
-rw-r--r--src/ccitt-adpcm/encode.c119
-rw-r--r--src/ccitt-adpcm/g711.c285
-rw-r--r--src/ccitt-adpcm/g721.c173
-rw-r--r--src/ccitt-adpcm/g723_24.c158
-rw-r--r--src/ccitt-adpcm/g723_40.c178
-rw-r--r--src/ccitt-adpcm/g72x.c565
-rw-r--r--src/ccitt-adpcm/g72x.h148
-rw-r--r--src/cli.c177
-rw-r--r--src/cmd-parser.y472
-rw-r--r--src/cmd-scanner.l182
-rw-r--r--src/debug.c2
-rw-r--r--src/dlc.c2
-rw-r--r--src/mac.c10
-rw-r--r--src/main.c58
-rw-r--r--src/nwk.c72
25 files changed, 3069 insertions, 23 deletions
diff --git a/Makefile.defs.in b/Makefile.defs.in
index af20d76..7d7579b 100644
--- a/Makefile.defs.in
+++ b/Makefile.defs.in
@@ -34,7 +34,7 @@ CFLAGS += -fstack-protector-all
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
CFLAGS += -Wdeclaration-after-statement -Wsign-compare -Winit-self
-CFLAGS += -Wformat-nonliteral -Wformat-security -Wmissing-format-attribute
+CFLAGS += -Wformat-nonliteral -Wformat-security # -Wmissing-format-attribute
CFLAGS += -Wcast-align -Wundef -Wbad-function-cast # -Wshadow
CFLAGS += -Waggregate-return -Wunused -Wwrite-strings
diff --git a/configure.ac b/configure.ac
index de64a46..5f939d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -25,6 +25,8 @@ AC_PROG_MKDIR_P
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_SED
+AC_PROG_LEX
+AC_PROG_YACC
AC_ARG_ENABLE([doc],
AS_HELP_STRING([--enable-doc], [build documentation [no]]),
@@ -47,6 +49,12 @@ AC_CHECK_LIB(ev, event_init,
EVENT_LDFLAGS=$EVENTLIB
AC_SUBST(EVENT_LDFLAGS)
+AC_CHECK_LIB([readline], [rl_callback_handler_install], ,
+ AC_MSG_ERROR([No suitable version of libreadline found]))
+
+AC_CHECK_LIB([SDL], [SDL_Init], ,
+ AC_MSG_ERROR([No suitable version of libSDL found]))
+
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_ASSERT
diff --git a/include/cli.h b/include/cli.h
new file mode 100644
index 0000000..f288719
--- /dev/null
+++ b/include/cli.h
@@ -0,0 +1,37 @@
+#ifndef DECTMON_CLI_H
+#define DECTMON_CLI_H
+
+#define YYLTYPE struct location
+#define YYLTYPE_IS_TRIVIAL 0
+#define YYENABLE_NLS 0
+
+struct location {
+ off_t token_offset;
+ off_t line_offset;
+
+ unsigned int first_line;
+ unsigned int last_line;
+ unsigned int first_column;
+ unsigned int last_column;
+};
+
+struct parser_state {
+ unsigned int lineno;
+ unsigned int column;
+ off_t token_offset;
+ off_t line_offset;
+};
+
+extern void parser_init(struct parser_state *state);
+extern int yyparse(void *, struct parser_state *state);
+
+extern void *scanner_init(struct parser_state *state);
+extern void scanner_destroy(struct parser_state *state);
+
+extern void scanner_push_buffer(void *scanner, const char *buffer);
+
+extern void cli_display(const char *fmt, va_list ap);
+extern int cli_init(FILE *file);
+extern void cli_exit(void);
+
+#endif /* DECTMON_CLI_H */
diff --git a/include/dectmon.h b/include/dectmon.h
index f916970..5a4684c 100644
--- a/include/dectmon.h
+++ b/include/dectmon.h
@@ -1,6 +1,7 @@
#ifndef _DECTMON_H
#define _DECTMON_H
+#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <list.h>
@@ -17,6 +18,7 @@ enum {
extern const char *auth_pin;
extern uint32_t dumpopts;
+extern uint32_t debug_mask;
struct dect_ops;
extern int dect_event_ops_init(struct dect_ops *ops);
@@ -25,15 +27,21 @@ extern void dect_event_loop(void);
extern void dect_event_ops_cleanup(void);
extern void dect_dummy_ops_init(struct dect_ops *ops);
+extern void dectmon_log(const char *fmt, ...);
extern void dect_hexdump(const char *prefix, const uint8_t *buf, size_t size);
+extern struct list_head dect_handles;
+
struct dect_handle_priv {
struct list_head list;
const char *cluster;
+ struct dect_handle *dh;
+
struct dect_timer *lock_timer;
+ bool locked;
struct dect_ari pari;
- struct list_head pt_list;
+ struct list_head pt_list;
struct dect_tbc *slots[DECT_FRAME_SIZE];
};
@@ -52,6 +60,8 @@ struct dect_pt {
uint8_t uak[DECT_AUTH_KEY_LEN];
uint8_t dck[DECT_CIPHER_KEY_LEN];
+ struct dect_audio_handle *ah;
+
enum dect_mm_procedures procedure;
uint8_t last_msg;
@@ -72,6 +82,9 @@ struct dect_msg_buf;
extern void dect_dl_data_ind(struct dect_handle *dh, struct dect_dl *dl,
struct dect_msg_buf *mb);
+extern void dect_dl_u_data_ind(struct dect_handle *dh, struct dect_dl *dl,
+ bool dir, struct dect_msg_buf *mb);
+
struct dect_lc {
uint16_t lsig;
struct dect_msg_buf *rx_buf;
@@ -121,4 +134,19 @@ extern void dect_dsc_keystream(uint64_t iv, const uint8_t *key,
uint8_t *output, unsigned int len);
extern uint64_t dect_dsc_iv(uint32_t mfn, uint8_t framenum);
+/* Audio */
+
+#include "../src/ccitt-adpcm/g72x.h"
+
+struct dect_audio_handle {
+ struct g72x_state codec[2];
+ struct dect_msg_buf *queue[2];
+};
+
+extern int dect_audio_init(void);
+extern struct dect_audio_handle *dect_audio_open(void);
+extern void dect_audio_close(struct dect_audio_handle *ah);
+extern void dect_audio_queue(struct dect_audio_handle *ah, unsigned int queue,
+ struct dect_msg_buf *mb);
+
#endif /* _DECTMON_H */
diff --git a/include/utils.h b/include/utils.h
new file mode 100644
index 0000000..5a7bbcb
--- /dev/null
+++ b/include/utils.h
@@ -0,0 +1,76 @@
+#ifndef _DECTMON_UTILS_H
+#define _DECTMON_UTILS_H
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define __init __attribute__((constructor))
+#define __exit __attribute__((destructor))
+#define __must_check __attribute__((warn_unused_result))
+#define __maybe_unused __attribute__((unused))
+#define __noreturn __attribute__((__noreturn__))
+#define __aligned(x) __attribute__((aligned(x)))
+#define __packed __attribute__((packed))
+#define __visible __attribute__((visibility("default")))
+
+#define BUG() assert(0)
+
+/* Force a compilation error if condition is true */
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1)
+
+#define __must_be_array(a) \
+ BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
+
+#define array_size(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+#define field_sizeof(t, f) (sizeof(((t *)NULL)->f))
+
+#define div_round_up(n, d) (((n) + (d) - 1) / (d))
+
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+
+static inline unsigned int fls(uint64_t v)
+{
+ unsigned int len = 0;
+
+ while (v) {
+ v >>= 1;
+ len++;
+ }
+ return len;
+}
+
+#define ptrlist_init(head) \
+ do { \
+ *(head) = NULL; \
+ } while (0)
+
+#define ptrlist_add_tail(new, head) \
+ do { \
+ typeof(new) *pprev; \
+ pprev = (head); \
+ while (*pprev != NULL) \
+ pprev = &(*pprev)->next; \
+ *pprev = new; \
+ } while (0)
+
+#define ptrlist_dequeue_head(head) \
+ ({ \
+ typeof(*head) elem = *(head); \
+ if (elem != NULL) \
+ *(head) = elem->next; \
+ elem; \
+ })
+
+#endif /* _DECTMON_UTILS_H */
diff --git a/src/.gitignore b/src/.gitignore
index f9e7749..5932393 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1 +1,4 @@
+cmd-parser.[ch]
+cmd-scanner.[ch]
+
dectmon
diff --git a/src/Makefile.in b/src/Makefile.in
index c89c94c..560b588 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -10,4 +10,12 @@ dectmon-obj += dsc.o
dectmon-obj += mac.o
dectmon-obj += dlc.o
dectmon-obj += nwk.o
+dectmon-obj += cmd-scanner.o
+dectmon-obj += cmd-parser.o
+dectmon-obj += cli.o
+dectmon-obj += audio.o
dectmon-obj += main.o
+
+dectmon-obj += ccitt-adpcm/g711.o
+dectmon-obj += ccitt-adpcm/g72x.o
+dectmon-obj += ccitt-adpcm/g721.o
diff --git a/src/audio.c b/src/audio.c
new file mode 100644
index 0000000..60338e2
--- /dev/null
+++ b/src/audio.c
@@ -0,0 +1,120 @@
+#include <SDL/SDL.h>
+#include <SDL/SDL_audio.h>
+
+#include <dectmon.h>
+#include <utils.h>
+
+void dect_audio_queue(struct dect_audio_handle *ah, unsigned int queue,
+ struct dect_msg_buf *mb)
+{
+ SDL_LockAudio();
+ ptrlist_add_tail(mb, &ah->queue[queue]);
+ SDL_UnlockAudio();
+}
+
+static void dect_decode_g721(struct g72x_state *codec,
+ int16_t *dst, const uint8_t *src,
+ unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len * 2; i += 2) {
+ dst[i + 0] = g721_decoder(src[i / 2] >> 4,
+ AUDIO_ENCODING_LINEAR, codec);
+ dst[i + 1] = g721_decoder(src[i / 2] & 0x0f,
+ AUDIO_ENCODING_LINEAR, codec);
+ }
+}
+
+static void dect_audio_dequeue(void *data, uint8_t *stream, int len)
+{
+ struct dect_audio_handle *ah = data;
+ struct dect_msg_buf *mb;
+ int16_t buf[len], *dptr;
+ unsigned int i, copy, n;
+
+ len /= 4;
+ for (i = 0; i < array_size(ah->queue); i++) {
+ dptr = buf;
+ n = len;
+
+ while (1) {
+ if (ah->queue[i] == NULL) {
+ dectmon_log("audio underrun queue %u, missing %u bytes\n",
+ i, n * 4);
+ memset(dptr, 0, n * 4);
+ break;
+ }
+
+ mb = ah->queue[i];
+ copy = mb->len;
+ if (copy > n)
+ copy = n;
+
+ dect_decode_g721(&ah->codec[i], dptr, mb->data, copy);
+ dect_mbuf_pull(mb, copy);
+ if (mb->len == 0) {
+ ah->queue[i] = mb->next;
+ free(mb);
+ }
+
+ n -= copy;
+ if (n == 0)
+ break;
+ dptr += 2 * copy;
+ }
+ SDL_MixAudio(stream, (uint8_t *)buf, 4 * len, SDL_MIX_MAXVOLUME);
+ }
+}
+
+struct dect_audio_handle *dect_audio_open(void)
+{
+ struct dect_audio_handle *ah;
+ SDL_AudioSpec spec = {
+ .freq = 8000,
+ .format = AUDIO_S16SYS,
+ .channels = 1,
+ .samples = 512,
+ .callback = dect_audio_dequeue,
+ };
+
+ ah = malloc(sizeof(*ah));
+ if (ah == NULL)
+ goto err1;
+
+ ptrlist_init(&ah->queue[0]);
+ g72x_init_state(&ah->codec[0]);
+
+ ptrlist_init(&ah->queue[1]);
+ g72x_init_state(&ah->codec[1]);
+
+ spec.userdata = ah;
+ if (SDL_OpenAudio(&spec, NULL) < 0)
+ goto err2;
+ SDL_PauseAudio(0);
+
+ return ah;
+
+err2:
+ free(ah);
+err1:
+ return NULL;
+}
+
+void dect_audio_close(struct dect_audio_handle *ah)
+{
+ struct dect_msg_buf *mb;
+ unsigned int i;
+
+ SDL_CloseAudio();
+ for (i = 0; i < array_size(ah->queue); i++) {
+ while ((mb = ptrlist_dequeue_head(&ah->queue[i])) != NULL)
+ free(mb);
+ }
+ free(ah);
+}
+
+int dect_audio_init(void)
+{
+ return SDL_Init(SDL_INIT_AUDIO);
+}
diff --git a/src/ccitt-adpcm/README b/src/ccitt-adpcm/README
new file mode 100644
index 0000000..23b0e7d
--- /dev/null
+++ b/src/ccitt-adpcm/README
@@ -0,0 +1,94 @@
+The files in this directory comprise ANSI-C language reference implementations
+of the CCITT (International Telegraph and Telephone Consultative Committee)
+G.711, G.721 and G.723 voice compressions. They have been tested on Sun
+SPARCstations and passed 82 out of 84 test vectors published by CCITT
+(Dec. 20, 1988) for G.721 and G.723. [The two remaining test vectors,
+which the G.721 decoder implementation for u-law samples did not pass,
+may be in error because they are identical to two other vectors for G.723_40.]
+
+This source code is released by Sun Microsystems, Inc. to the public domain.
+Please give your acknowledgement in product literature if this code is used
+in your product implementation.
+
+Sun Microsystems supports some CCITT audio formats in Solaris 2.0 system
+software. However, Sun's implementations have been optimized for higher
+performance on SPARCstations.
+
+
+The source files for CCITT conversion routines in this directory are:
+
+ g72x.h header file for g721.c, g723_24.c and g723_40.c
+ g711.c CCITT G.711 u-law and A-law compression
+ g72x.c common denominator of G.721 and G.723 ADPCM codes
+ g721.c CCITT G.721 32Kbps ADPCM coder (with g72x.c)
+ g723_24.c CCITT G.723 24Kbps ADPCM coder (with g72x.c)
+ g723_40.c CCITT G.723 40Kbps ADPCM coder (with g72x.c)
+
+
+Simple conversions between u-law, A-law, and 16-bit linear PCM are invoked
+as follows:
+
+ unsigned char ucode, acode;
+ short pcm_val;
+
+ ucode = linear2ulaw(pcm_val);
+ ucode = alaw2ulaw(acode);
+
+ acode = linear2alaw(pcm_val);
+ acode = ulaw2alaw(ucode);
+
+ pcm_val = ulaw2linear(ucode);
+ pcm_val = alaw2linear(acode);
+
+
+The other CCITT compression routines are invoked as follows:
+
+ #include "g72x.h"
+
+ struct g72x_state state;
+ int sample, code;
+
+ g72x_init_state(&state);
+ code = {g721,g723_24,g723_40}_encoder(sample, coding, &state);
+ sample = {g721,g723_24,g723_40}_decoder(code, coding, &state);
+
+where
+ coding = AUDIO_ENCODING_ULAW for 8-bit u-law samples
+ AUDIO_ENCODING_ALAW for 8-bit A-law samples
+ AUDIO_ENCODING_LINEAR for 16-bit linear PCM samples
+
+
+
+This directory also includes the following sample programs:
+
+ encode.c CCITT ADPCM encoder
+ decode.c CCITT ADPCM decoder
+ Makefile makefile for the sample programs
+
+
+The sample programs contain examples of how to call the various compression
+routines and pack/unpack the bits. The sample programs read byte streams from
+stdin and write to stdout. The input/output data is raw data (no file header
+or other identifying information is embedded). The sample programs are
+invoked as follows:
+
+ encode [-3|4|5] [-a|u|l] <infile >outfile
+ decode [-3|4|5] [-a|u|l] <infile >outfile
+where:
+ -3 encode to (decode from) G.723 24kbps (3-bit) data
+ -4 encode to (decode from) G.721 32kbps (4-bit) data [the default]
+ -5 encode to (decode from) G.723 40kbps (5-bit) data
+ -a encode from (decode to) A-law data
+ -u encode from (decode to) u-law data [the default]
+ -l encode from (decode to) 16-bit linear data
+
+Examples:
+ # Read 16-bit linear and output G.721
+ encode -4 -l <pcmfile >g721file
+
+ # Read 40Kbps G.723 and output A-law
+ decode -5 -a <g723file >alawfile
+
+ # Compress and then decompress u-law data using 24Kbps G.723
+ encode -3 <ulawin | deoced -3 >ulawout
+
diff --git a/src/ccitt-adpcm/decode.c b/src/ccitt-adpcm/decode.c
new file mode 100644
index 0000000..cf8c739
--- /dev/null
+++ b/src/ccitt-adpcm/decode.c
@@ -0,0 +1,113 @@
+/*
+ * decode.c
+ *
+ * CCITT ADPCM decoder
+ *
+ * Usage : decode [-3|4|5] [-a|u|l] < infile > outfile
+ */
+#include <stdio.h>
+#include "g72x.h"
+
+
+/*
+ * Unpack input codes and pass them back as bytes.
+ * Returns 1 if there is residual input, returns -1 if eof, else returns 0.
+ */
+int
+unpack_input(
+ unsigned char *code,
+ int bits)
+{
+ static unsigned int in_buffer = 0;
+ static int in_bits = 0;
+ unsigned char in_byte;
+
+ if (in_bits < bits) {
+ if (fread(&in_byte, sizeof (char), 1, stdin) != 1) {
+ *code = 0;
+ return (-1);
+ }
+ in_buffer |= (in_byte << in_bits);
+ in_bits += 8;
+ }
+ *code = in_buffer & ((1 << bits) - 1);
+ in_buffer >>= bits;
+ in_bits -= bits;
+ return (in_bits > 0);
+}
+
+
+main(
+ int argc,
+ char **argv)
+{
+ short sample;
+ unsigned char code;
+ int n;
+ struct g72x_state state;
+ int out_coding;
+ int out_size;
+ int (*dec_routine)();
+ int dec_bits;
+
+ g72x_init_state(&state);
+ out_coding = AUDIO_ENCODING_ULAW;
+ out_size = sizeof (char);
+ dec_routine = g721_decoder;
+ dec_bits = 4;
+
+ /* Process encoding argument, if any */
+ while ((argc > 1) && (argv[1][0] == '-')) {
+ switch (argv[1][1]) {
+ case '3':
+ dec_routine = g723_24_decoder;
+ dec_bits = 3;
+ break;
+ case '4':
+ dec_routine = g721_decoder;
+ dec_bits = 4;
+ break;
+ case '5':
+ dec_routine = g723_40_decoder;
+ dec_bits = 5;
+ break;
+ case 'u':
+ out_coding = AUDIO_ENCODING_ULAW;
+ out_size = sizeof (char);
+ break;
+ case 'a':
+ out_coding = AUDIO_ENCODING_ALAW;
+ out_size = sizeof (char);
+ break;
+ case 'l':
+ out_coding = AUDIO_ENCODING_LINEAR;
+ out_size = sizeof (short);
+ break;
+ default:
+fprintf(stderr, "CCITT ADPCM Decoder -- usage:\n");
+fprintf(stderr, "\tdecode [-3|4|5] [-a|u|l] < infile > outfile\n");
+fprintf(stderr, "where:\n");
+fprintf(stderr, "\t-3\tProcess G.723 24kbps (3-bit) input data\n");
+fprintf(stderr, "\t-4\tProcess G.721 32kbps (4-bit) input data [default]\n");
+fprintf(stderr, "\t-5\tProcess G.723 40kbps (5-bit) input data\n");
+fprintf(stderr, "\t-a\tGenerate 8-bit A-law data\n");
+fprintf(stderr, "\t-u\tGenerate 8-bit u-law data [default]\n");
+fprintf(stderr, "\t-l\tGenerate 16-bit linear PCM data\n");
+ exit(1);
+ }
+ argc--;
+ argv++;
+ }
+
+ /* Read and unpack input codes and process them */
+ while (unpack_input(&code, dec_bits) >= 0) {
+ sample = (*dec_routine)(code, out_coding, &state);
+ if (out_size == 2) {
+ fwrite(&sample, out_size, 1, stdout);
+ } else {
+ code = (unsigned char)sample;
+ fwrite(&code, out_size, 1, stdout);
+ }
+ }
+ fclose(stdout);
+}
diff --git a/src/ccitt-adpcm/encode.c b/src/ccitt-adpcm/encode.c
new file mode 100644
index 0000000..571fbe8
--- /dev/null
+++ b/src/ccitt-adpcm/encode.c
@@ -0,0 +1,119 @@
+/*
+ * encode.c
+ *
+ * CCITT ADPCM encoder
+ *
+ * Usage : encode [-3|4|5] [-a|u|l] < infile > outfile
+ */
+#include <stdio.h>
+#include "g72x.h"
+
+
+/*
+ * Pack output codes into bytes and write them to stdout.
+ * Returns 1 if there is residual output, else returns 0.
+ */
+int
+pack_output(
+ unsigned code,
+ int bits)
+{
+ static unsigned int out_buffer = 0;
+ static int out_bits = 0;
+ unsigned char out_byte;
+
+ out_buffer |= (code << out_bits);
+ out_bits += bits;
+ if (out_bits >= 8) {
+ out_byte = out_buffer & 0xff;
+ out_bits -= 8;
+ out_buffer >>= 8;
+ fwrite(&out_byte, sizeof (char), 1, stdout);
+ }
+ return (out_bits > 0);
+}
+
+
+main(
+ int argc,
+ char **argv)
+{
+ struct g72x_state state;
+ unsigned char sample_char;
+ short sample_short;
+ unsigned char code;
+ int resid;
+ int in_coding;
+ int in_size;
+ unsigned *in_buf;
+ int (*enc_routine)();
+ int enc_bits;
+
+ g72x_init_state(&state);
+
+ /* Set defaults to u-law input, G.721 output */
+ in_coding = AUDIO_ENCODING_ULAW;
+ in_size = sizeof (char);
+ in_buf = (unsigned *)&sample_char;
+ enc_routine = g721_encoder;
+ enc_bits = 4;
+
+ /* Process encoding argument, if any */
+ while ((argc > 1) && (argv[1][0] == '-')) {
+ switch (argv[1][1]) {
+ case '3':
+ enc_routine = g723_24_encoder;
+ enc_bits = 3;
+ break;
+ case '4':
+ enc_routine = g721_encoder;
+ enc_bits = 4;
+ break;
+ case '5':
+ enc_routine = g723_40_encoder;
+ enc_bits = 5;
+ break;
+ case 'u':
+ in_coding = AUDIO_ENCODING_ULAW;
+ in_size = sizeof (char);
+ in_buf = (unsigned *)&sample_char;
+ break;
+ case 'a':
+ in_coding = AUDIO_ENCODING_ALAW;
+ in_size = sizeof (char);
+ in_buf = (unsigned *)&sample_char;
+ break;
+ case 'l':
+ in_coding = AUDIO_ENCODING_LINEAR;
+ in_size = sizeof (short);
+ in_buf = (unsigned *)&sample_short;
+ break;
+ default:
+fprintf(stderr, "CCITT ADPCM Encoder -- usage:\n");
+fprintf(stderr, "\tencode [-3|4|5] [-a|u|l] < infile > outfile\n");
+fprintf(stderr, "where:\n");
+fprintf(stderr, "\t-3\tGenerate G.723 24kbps (3-bit) data\n");
+fprintf(stderr, "\t-4\tGenerate G.721 32kbps (4-bit) data [default]\n");
+fprintf(stderr, "\t-5\tGenerate G.723 40kbps (5-bit) data\n");
+fprintf(stderr, "\t-a\tProcess 8-bit A-law input data\n");
+fprintf(stderr, "\t-u\tProcess 8-bit u-law input data [default]\n");
+fprintf(stderr, "\t-l\tProcess 16-bit linear PCM input data\n");
+ exit(1);
+ }
+ argc--;
+ argv++;
+ }
+
+ /* Read input file and process */
+ while (fread(in_buf, in_size, 1, stdin) == 1) {
+ code = (*enc_routine)(in_size == 2 ? sample_short : sample_char,
+ in_coding, &state);
+ resid = pack_output(code, enc_bits);
+ }
+
+ /* Write zero codes until all residual codes are written out */
+ while (resid) {
+ resid = pack_output(0, enc_bits);
+ }
+ fclose(stdout);
+}
diff --git a/src/ccitt-adpcm/g711.c b/src/ccitt-adpcm/g711.c
new file mode 100644
index 0000000..f9eab50
--- /dev/null
+++ b/src/ccitt-adpcm/g711.c
@@ -0,0 +1,285 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include "g72x.h"
+
+/*
+ * g711.c
+ *
+ * u-law, A-law and linear PCM conversions.
+ */
+#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
+#define QUANT_MASK (0xf) /* Quantization field mask. */
+#define NSEGS (8) /* Number of A-law segments. */
+#define SEG_SHIFT (4) /* Left shift for segment number. */
+#define SEG_MASK (0x70) /* Segment field mask. */
+
+static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
+
+/* copy from CCITT G.711 specifications */
+unsigned char _u2a[128] = { /* u- to A-law conversions */
+ 1, 1, 2, 2, 3, 3, 4, 4,
+ 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 27, 29, 31, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44,
+ 46, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128};
+
+unsigned char _a2u[128] = { /* A- to u-law conversions */
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 48, 49, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127};
+
+static int
+search(
+ int val,
+ short *table,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (val <= *table++)
+ return (i);
+ }
+ return (size);
+}
+
+/*
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ * Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+linear2alaw(
+ int pcm_val) /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char aval;
+
+ if (pcm_val >= 0) {
+ mask = 0xD5; /* sign (7th) bit = 1 */
+ } else {
+ mask = 0x55; /* sign bit = 0 */
+ pcm_val = -pcm_val - 8;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /* Combine the sign, segment, and quantization bits. */
+
+ if (seg >= 8) /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ else {
+ aval = seg << SEG_SHIFT;
+ if (seg < 2)
+ aval |= (pcm_val >> 4) & QUANT_MASK;
+ else
+ aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
+ return (aval ^ mask);
+ }
+}
+
+/*
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+int
+alaw2linear(
+ unsigned char a_val)
+{
+ int t;
+ int seg;
+
+ a_val ^= 0x55;
+
+ t = (a_val & QUANT_MASK) << 4;
+ seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+ switch (seg) {
+ case 0:
+ t += 8;
+ break;
+ case 1:
+ t += 0x108;
+ break;
+ default:
+ t += 0x108;
+ t <<= seg - 1;
+ }
+ return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+#define BIAS (0x84) /* Bias for linear code. */
+
+/*
+ * linear2ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+linear2ulaw(
+ int pcm_val) /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char uval;
+
+ /* Get the sign and the magnitude of the value. */
+ if (pcm_val < 0) {
+ pcm_val = BIAS - pcm_val;
+ mask = 0x7F;
+ } else {
+ pcm_val += BIAS;
+ mask = 0xFF;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /*
+ * Combine the sign, segment, quantization bits;
+ * and complement the code word.
+ */
+ if (seg >= 8) /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ else {
+ uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
+ return (uval ^ mask);
+ }
+
+}
+
+/*
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+int
+ulaw2linear(
+ unsigned char u_val)
+{
+ int t;
+
+ /* Complement to obtain normal u-law value. */
+ u_val = ~u_val;
+
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = ((u_val & QUANT_MASK) << 3) + BIAS;
+ t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+
+ return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+}
+
+/* A-law to u-law conversion */
+unsigned char
+alaw2ulaw(
+ unsigned char aval)
+{
+ aval &= 0xff;
+ return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+ (0x7F ^ _a2u[aval ^ 0x55]));
+}
+
+/* u-law to A-law conversion */
+unsigned char
+ulaw2alaw(
+ unsigned char uval)
+{
+ uval &= 0xff;
+ return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+ (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+}
diff --git a/src/ccitt-adpcm/g721.c b/src/ccitt-adpcm/g721.c
new file mode 100644
index 0000000..445f177
--- /dev/null
+++ b/src/ccitt-adpcm/g721.c
@@ -0,0 +1,173 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g721.c
+ *
+ * Description:
+ *
+ * g721_encoder(), g721_decoder()
+ *
+ * These routines comprise an implementation of the CCITT G.721 ADPCM
+ * coding algorithm. Essentially, this implementation is identical to
+ * the bit level description except for a few deviations which
+ * take advantage of work station attributes, such as hardware 2's
+ * complement arithmetic and large memory. Specifically, certain time
+ * consuming operations such as multiplications are replaced
+ * with lookup tables and software 2's complement operations are
+ * replaced with hardware 2's complement.
+ *
+ * The deviation from the bit level specification (lookup tables)
+ * preserves the bit level performance specifications.
+ *
+ * As outlined in the G.721 Recommendation, the algorithm is broken
+ * down into modules. Each section of code below is preceded by
+ * the name of the module which it is implementing.
+ *
+ */
+#include "g72x.h"
+
+static short qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400};
+/*
+ * Maps G.721 code word to reconstructed scale factor normalized log
+ * magnitude values.
+ */
+static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425,
+ 425, 373, 323, 273, 213, 135, 4, -2048};
+
+/* Maps G.721 code word to log of scale factor multiplier. */
+static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122,
+ 1122, 355, 198, 112, 64, 41, 18, -12};
+/*
+ * Maps G.721 code words to a set of values whose long and short
+ * term averages are computed and then compared to give an indication
+ * how stationary (steady state) the signal is.
+ */
+static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
+ 0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0};
+
+/*
+ * g721_encoder()
+ *
+ * Encodes the input vale of linear PCM, A-law or u-law data sl and returns
+ * the resulting code. -1 is returned for unknown input coding value.
+ */
+int
+g721_encoder(
+ int sl,
+ int in_coding,
+ struct g72x_state *state_ptr)
+{
+ short sezi, se, sez; /* ACCUM */
+ short d; /* SUBTA */
+ short sr; /* ADDB */
+ short y; /* MIX */
+ short dqsez; /* ADDC */
+ short dq, i;
+
+ switch (in_coding) { /* linearize input sample to 14-bit PCM */
+ case AUDIO_ENCODING_ALAW:
+ sl = alaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_ULAW:
+ sl = ulaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ sl >>= 2; /* 14-bit dynamic range */
+ break;
+ default:
+ return (-1);
+ }
+
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */
+
+ d = sl - se; /* estimation difference */
+
+ /* quantize the prediction difference */
+ y = step_size(state_ptr); /* quantizer step size */
+ i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */
+
+ dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */
+
+ sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */
+
+ dqsez = sr + sez - se; /* pole prediction diff. */
+
+ update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
+
+ return (i);
+}
+
+/*
+ * g721_decoder()
+ *
+ * Description:
+ *
+ * Decodes a 4-bit code of G.721 encoded data of i and
+ * returns the resulting linear PCM, A-law or u-law value.
+ * return -1 for unknown out_coding value.
+ */
+int
+g721_decoder(
+ int i,
+ int out_coding,
+ struct g72x_state *state_ptr)
+{
+ short sezi, sei, sez, se; /* ACCUM */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dq;
+ short dqsez;
+
+ i &= 0x0f; /* mask to get proper bits */
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ y = step_size(state_ptr); /* dynamic quantizer step size */
+
+ dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
+
+ sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
+
+ dqsez = sr - se + sez; /* pole prediction diff. */
+
+ update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
+
+ switch (out_coding) {
+ case AUDIO_ENCODING_ALAW:
+ return (tandem_adjust_alaw(sr, se, y, i, 8, qtab_721));
+ case AUDIO_ENCODING_ULAW:
+ return (tandem_adjust_ulaw(sr, se, y, i, 8, qtab_721));
+ case AUDIO_ENCODING_LINEAR:
+ return (sr << 2); /* sr was 14-bit dynamic range */
+ default:
+ return (-1);
+ }
+}
diff --git a/src/ccitt-adpcm/g723_24.c b/src/ccitt-adpcm/g723_24.c
new file mode 100644
index 0000000..452f4da
--- /dev/null
+++ b/src/ccitt-adpcm/g723_24.c
@@ -0,0 +1,158 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g723_24.c
+ *
+ * Description:
+ *
+ * g723_24_encoder(), g723_24_decoder()
+ *
+ * These routines comprise an implementation of the CCITT G.723 24 Kbps
+ * ADPCM coding algorithm. Essentially, this implementation is identical to
+ * the bit level description except for a few deviations which take advantage
+ * of workstation attributes, such as hardware 2's complement arithmetic.
+ *
+ */
+#include "g72x.h"
+
+/*
+ * Maps G.723_24 code word to reconstructed scale factor normalized log
+ * magnitude values.
+ */
+static short _dqlntab[8] = {-2048, 135, 273, 373, 373, 273, 135, -2048};
+
+/* Maps G.723_24 code word to log of scale factor multiplier. */
+static short _witab[8] = {-128, 960, 4384, 18624, 18624, 4384, 960, -128};
+
+/*
+ * Maps G.723_24 code words to a set of values whose long and short
+ * term averages are computed and then compared to give an indication
+ * how stationary (steady state) the signal is.
+ */
+static short _fitab[8] = {0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0};
+
+static short qtab_723_24[3] = {8, 218, 331};
+
+/*
+ * g723_24_encoder()
+ *
+ * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code.
+ * Returns -1 if invalid input coding value.
+ */
+int
+g723_24_encoder(
+ int sl,
+ int in_coding,
+ struct g72x_state *state_ptr)
+{
+ short sei, sezi, se, sez; /* ACCUM */
+ short d; /* SUBTA */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dqsez; /* ADDC */
+ short dq, i;
+
+ switch (in_coding) { /* linearize input sample to 14-bit PCM */
+ case AUDIO_ENCODING_ALAW:
+ sl = alaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_ULAW:
+ sl = ulaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ sl >>= 2; /* sl of 14-bit dynamic range */
+ break;
+ default:
+ return (-1);
+ }
+
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ d = sl - se; /* d = estimation diff. */
+
+ /* quantize prediction difference d */
+ y = step_size(state_ptr); /* quantizer step size */
+ i = quantize(d, y, qtab_723_24, 3); /* i = ADPCM code */
+ dq = reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */
+
+ sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */
+
+ dqsez = sr + sez - se; /* pole prediction diff. */
+
+ update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
+
+ return (i);
+}
+
+/*
+ * g723_24_decoder()
+ *
+ * Decodes a 3-bit CCITT G.723_24 ADPCM code and returns
+ * the resulting 16-bit linear PCM, A-law or u-law sample value.
+ * -1 is returned if the output coding is unknown.
+ */
+int
+g723_24_decoder(
+ int i,
+ int out_coding,
+ struct g72x_state *state_ptr)
+{
+ short sezi, sei, sez, se; /* ACCUM */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dq;
+ short dqsez;
+
+ i &= 0x07; /* mask to get proper bits */
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ y = step_size(state_ptr); /* adaptive quantizer step size */
+ dq = reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */
+
+ sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */
+
+ dqsez = sr - se + sez; /* pole prediction diff. */
+
+ update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
+
+ switch (out_coding) {
+ case AUDIO_ENCODING_ALAW:
+ return (tandem_adjust_alaw(sr, se, y, i, 4, qtab_723_24));
+ case AUDIO_ENCODING_ULAW:
+ return (tandem_adjust_ulaw(sr, se, y, i, 4, qtab_723_24));
+ case AUDIO_ENCODING_LINEAR:
+ return (sr << 2); /* sr was of 14-bit dynamic range */
+ default:
+ return (-1);
+ }
+}
diff --git a/src/ccitt-adpcm/g723_40.c b/src/ccitt-adpcm/g723_40.c
new file mode 100644
index 0000000..4858baf
--- /dev/null
+++ b/src/ccitt-adpcm/g723_40.c
@@ -0,0 +1,178 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g723_40.c
+ *
+ * Description:
+ *
+ * g723_40_encoder(), g723_40_decoder()
+ *
+ * These routines comprise an implementation of the CCITT G.723 40Kbps
+ * ADPCM coding algorithm. Essentially, this implementation is identical to
+ * the bit level description except for a few deviations which
+ * take advantage of workstation attributes, such as hardware 2's
+ * complement arithmetic.
+ *
+ * The deviation from the bit level specification (lookup tables),
+ * preserves the bit level performance specifications.
+ *
+ * As outlined in the G.723 Recommendation, the algorithm is broken
+ * down into modules. Each section of code below is preceded by
+ * the name of the module which it is implementing.
+ *
+ */
+#include "g72x.h"
+
+/*
+ * Maps G.723_40 code word to ructeconstructed scale factor normalized log
+ * magnitude values.
+ */
+static short _dqlntab[32] = {-2048, -66, 28, 104, 169, 224, 274, 318,
+ 358, 395, 429, 459, 488, 514, 539, 566,
+ 566, 539, 514, 488, 459, 429, 395, 358,
+ 318, 274, 224, 169, 104, 28, -66, -2048};
+
+/* Maps G.723_40 code word to log of scale factor multiplier. */
+static short _witab[32] = {448, 448, 768, 1248, 1280, 1312, 1856, 3200,
+ 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272,
+ 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512,
+ 3200, 1856, 1312, 1280, 1248, 768, 448, 448};
+
+/*
+ * Maps G.723_40 code words to a set of values whose long and short
+ * term averages are computed and then compared to give an indication
+ * how stationary (steady state) the signal is.
+ */
+static short _fitab[32] = {0, 0, 0, 0, 0, 0x200, 0x200, 0x200,
+ 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00,
+ 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200,
+ 0x200, 0x200, 0x200, 0, 0, 0, 0, 0};
+
+static short qtab_723_40[15] = {-122, -16, 68, 139, 198, 250, 298, 339,
+ 378, 413, 445, 475, 502, 528, 553};
+
+/*
+ * g723_40_encoder()
+ *
+ * Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens
+ * the resulting 5-bit CCITT G.723 40Kbps code.
+ * Returns -1 if the input coding value is invalid.
+ */
+int
+g723_40_encoder(
+ int sl,
+ int in_coding,
+ struct g72x_state *state_ptr)
+{
+ short sei, sezi, se, sez; /* ACCUM */
+ short d; /* SUBTA */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dqsez; /* ADDC */
+ short dq, i;
+
+ switch (in_coding) { /* linearize input sample to 14-bit PCM */
+ case AUDIO_ENCODING_ALAW:
+ sl = alaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_ULAW:
+ sl = ulaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ sl >>= 2; /* sl of 14-bit dynamic range */
+ break;
+ default:
+ return (-1);
+ }
+
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ d = sl - se; /* d = estimation difference */
+
+ /* quantize prediction difference */
+ y = step_size(state_ptr); /* adaptive quantizer step size */
+ i = quantize(d, y, qtab_723_40, 15); /* i = ADPCM code */
+
+ dq = reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */
+
+ sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq; /* reconstructed signal */
+
+ dqsez = sr + sez - se; /* dqsez = pole prediction diff. */
+
+ update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
+
+ return (i);
+}
+
+/*
+ * g723_40_decoder()
+ *
+ * Decodes a 5-bit CCITT G.723 40Kbps code and returns
+ * the resulting 16-bit linear PCM, A-law or u-law sample value.
+ * -1 is returned if the output coding is unknown.
+ */
+int
+g723_40_decoder(
+ int i,
+ int out_coding,
+ struct g72x_state *state_ptr)
+{
+ short sezi, sei, sez, se; /* ACCUM */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dq;
+ short dqsez;
+
+ i &= 0x1f; /* mask to get proper bits */
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ y = step_size(state_ptr); /* adaptive quantizer step size */
+ dq = reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */
+
+ sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); /* reconst. signal */
+
+ dqsez = sr - se + sez; /* pole prediction diff. */
+
+ update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
+
+ switch (out_coding) {
+ case AUDIO_ENCODING_ALAW:
+ return (tandem_adjust_alaw(sr, se, y, i, 0x10, qtab_723_40));
+ case AUDIO_ENCODING_ULAW:
+ return (tandem_adjust_ulaw(sr, se, y, i, 0x10, qtab_723_40));
+ case AUDIO_ENCODING_LINEAR:
+ return (sr << 2); /* sr was of 14-bit dynamic range */
+ default:
+ return (-1);
+ }
+}
diff --git a/src/ccitt-adpcm/g72x.c b/src/ccitt-adpcm/g72x.c
new file mode 100644
index 0000000..ca17c35
--- /dev/null
+++ b/src/ccitt-adpcm/g72x.c
@@ -0,0 +1,565 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g72x.c
+ *
+ * Common routines for G.721 and G.723 conversions.
+ */
+
+#include <stdlib.h>
+#include "g72x.h"
+
+static short power2[15] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
+ 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000};
+
+/*
+ * quan()
+ *
+ * quantizes the input val against the table of size short integers.
+ * It returns i if table[i - 1] <= val < table[i].
+ *
+ * Using linear search for simple coding.
+ */
+static int
+quan(
+ int val,
+ short *table,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ if (val < *table++)
+ break;
+ return (i);
+}
+
+/*
+ * fmult()
+ *
+ * returns the integer product of the 14-bit integer "an" and
+ * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
+ */
+static int
+fmult(
+ int an,
+ int srn)
+{
+ short anmag, anexp, anmant;
+ short wanexp, wanmant;
+ short retval;
+
+ anmag = (an > 0) ? an : ((-an) & 0x1FFF);
+ anexp = quan(anmag, power2, 15) - 6;
+ anmant = (anmag == 0) ? 32 :
+ (anexp >= 0) ? anmag >> anexp : anmag << -anexp;
+ wanexp = anexp + ((srn >> 6) & 0xF) - 13;
+
+ wanmant = (anmant * (srn & 077) + 0x30) >> 4;
+ retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
+ (wanmant >> -wanexp);
+
+ return (((an ^ srn) < 0) ? -retval : retval);
+}
+
+/*
+ * g72x_init_state()
+ *
+ * This routine initializes and/or resets the g72x_state structure
+ * pointed to by 'state_ptr'.
+ * All the initial state values are specified in the CCITT G.721 document.
+ */
+void
+g72x_init_state(
+ struct g72x_state *state_ptr)
+{
+ int cnta;
+
+ state_ptr->yl = 34816;
+ state_ptr->yu = 544;
+ state_ptr->dms = 0;
+ state_ptr->dml = 0;
+ state_ptr->ap = 0;
+ for (cnta = 0; cnta < 2; cnta++) {
+ state_ptr->a[cnta] = 0;
+ state_ptr->pk[cnta] = 0;
+ state_ptr->sr[cnta] = 32;
+ }
+ for (cnta = 0; cnta < 6; cnta++) {
+ state_ptr->b[cnta] = 0;
+ state_ptr->dq[cnta] = 32;
+ }
+ state_ptr->td = 0;
+}
+
+/*
+ * predictor_zero()
+ *
+ * computes the estimated signal from 6-zero predictor.
+ *
+ */
+int
+predictor_zero(
+ struct g72x_state *state_ptr)
+{
+ int i;
+ int sezi;
+
+ sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
+ for (i = 1; i < 6; i++) /* ACCUM */
+ sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
+ return (sezi);
+}
+/*
+ * predictor_pole()
+ *
+ * computes the estimated signal from 2-pole predictor.
+ *
+ */
+int
+predictor_pole(
+ struct g72x_state *state_ptr)
+{
+ return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
+ fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
+}
+/*
+ * step_size()
+ *
+ * computes the quantization step size of the adaptive quantizer.
+ *
+ */
+int
+step_size(
+ struct g72x_state *state_ptr)
+{
+ int y;
+ int dif;
+ int al;
+
+ if (state_ptr->ap >= 256)
+ return (state_ptr->yu);
+ else {
+ y = state_ptr->yl >> 6;
+ dif = state_ptr->yu - y;
+ al = state_ptr->ap >> 2;
+ if (dif > 0)
+ y += (dif * al) >> 6;
+ else if (dif < 0)
+ y += (dif * al + 0x3F) >> 6;
+ return (y);
+ }
+}
+
+/*
+ * quantize()
+ *
+ * Given a raw sample, 'd', of the difference signal and a
+ * quantization step size scale factor, 'y', this routine returns the
+ * ADPCM codeword to which that sample gets quantized. The step
+ * size scale factor division operation is done in the log base 2 domain
+ * as a subtraction.
+ */
+int
+quantize(
+ int d, /* Raw difference signal sample */
+ int y, /* Step size multiplier */
+ short *table, /* quantization table */
+ int size) /* table size of short integers */
+{
+ short dqm; /* Magnitude of 'd' */
+ short exp; /* Integer part of base 2 log of 'd' */
+ short mant; /* Fractional part of base 2 log */
+ short dl; /* Log of magnitude of 'd' */
+ short dln; /* Step size scale factor normalized log */
+ int i;
+
+ /*
+ * LOG
+ *
+ * Compute base 2 log of 'd', and store in 'dl'.
+ */
+ dqm = abs(d);
+ exp = quan(dqm >> 1, power2, 15);
+ mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */
+ dl = (exp << 7) + mant;
+
+ /*
+ * SUBTB
+ *
+ * "Divide" by step size multiplier.
+ */
+ dln = dl - (y >> 2);
+
+ /*
+ * QUAN
+ *
+ * Obtain codword i for 'd'.
+ */
+ i = quan(dln, table, size);
+ if (d < 0) /* take 1's complement of i */
+ return ((size << 1) + 1 - i);
+ else if (i == 0) /* take 1's complement of 0 */
+ return ((size << 1) + 1); /* new in 1988 */
+ else
+ return (i);
+}
+/*
+ * reconstruct()
+ *
+ * Returns reconstructed difference signal 'dq' obtained from
+ * codeword 'i' and quantization step size scale factor 'y'.
+ * Multiplication is performed in log base 2 domain as addition.
+ */
+int
+reconstruct(
+ int sign, /* 0 for non-negative value */
+ int dqln, /* G.72x codeword */
+ int y) /* Step size multiplier */
+{
+ short dql; /* Log of 'dq' magnitude */
+ short dex; /* Integer part of log */
+ short dqt;
+ short dq; /* Reconstructed difference signal sample */
+
+ dql = dqln + (y >> 2); /* ADDA */
+
+ if (dql < 0) {
+ return ((sign) ? -0x8000 : 0);
+ } else { /* ANTILOG */
+ dex = (dql >> 7) & 15;
+ dqt = 128 + (dql & 127);
+ dq = (dqt << 7) >> (14 - dex);
+ return ((sign) ? (dq - 0x8000) : dq);
+ }
+}
+
+
+/*
+ * update()
+ *
+ * updates the state variables for each output code
+ */
+void
+update(
+ int code_size, /* distinguish 723_40 with others */
+ int y, /* quantizer step size */
+ int wi, /* scale factor multiplier */
+ int fi, /* for long/short term energies */
+ int dq, /* quantized prediction difference */
+ int sr, /* reconstructed signal */
+ int dqsez, /* difference from 2-pole predictor */
+ struct g72x_state *state_ptr) /* coder state pointer */
+{
+ int cnt;
+ short mag, exp; /* Adaptive predictor, FLOAT A */
+ short a2p = 0; /* LIMC */
+ short a1ul; /* UPA1 */
+ short pks1; /* UPA2 */
+ short fa1;
+ char tr; /* tone/transition detector */
+ short ylint, thr2, dqthr;
+ short ylfrac, thr1;
+ short pk0;
+
+ pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
+
+ mag = dq & 0x7FFF; /* prediction difference magnitude */
+ /* TRANS */
+ ylint = state_ptr->yl >> 15; /* exponent part of yl */
+ ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
+ thr1 = (32 + ylfrac) << ylint; /* threshold */
+ thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */
+ dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */
+ if (state_ptr->td == 0) /* signal supposed voice */
+ tr = 0;
+ else if (mag <= dqthr) /* supposed data, but small mag */
+ tr = 0; /* treated as voice */
+ else /* signal is data (modem) */
+ tr = 1;
+
+ /*
+ * Quantizer scale factor adaptation.
+ */
+
+ /* FUNCTW & FILTD & DELAY */
+ /* update non-steady state step size multiplier */
+ state_ptr->yu = y + ((wi - y) >> 5);
+
+ /* LIMB */
+ if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
+ state_ptr->yu = 544;
+ else if (state_ptr->yu > 5120)
+ state_ptr->yu = 5120;
+
+ /* FILTE & DELAY */
+ /* update steady state step size multiplier */
+ state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
+
+ /*
+ * Adaptive predictor coefficients.
+ */
+ if (tr == 1) { /* reset a's and b's for modem signal */
+ state_ptr->a[0] = 0;
+ state_ptr->a[1] = 0;
+ state_ptr->b[0] = 0;
+ state_ptr->b[1] = 0;
+ state_ptr->b[2] = 0;
+ state_ptr->b[3] = 0;
+ state_ptr->b[4] = 0;
+ state_ptr->b[5] = 0;
+ } else { /* update a's and b's */
+ pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
+
+ /* update predictor pole a[1] */
+ a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
+ if (dqsez != 0) {
+ fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
+ if (fa1 < -8191) /* a2p = function of fa1 */
+ a2p -= 0x100;
+ else if (fa1 > 8191)
+ a2p += 0xFF;
+ else
+ a2p += fa1 >> 5;
+
+ if (pk0 ^ state_ptr->pk[1])
+ /* LIMC */
+ if (a2p <= -12160)
+ a2p = -12288;
+ else if (a2p >= 12416)
+ a2p = 12288;
+ else
+ a2p -= 0x80;
+ else if (a2p <= -12416)
+ a2p = -12288;
+ else if (a2p >= 12160)
+ a2p = 12288;
+ else
+ a2p += 0x80;
+ }
+
+ /* TRIGB & DELAY */
+ state_ptr->a[1] = a2p;
+
+ /* UPA1 */
+ /* update predictor pole a[0] */
+ state_ptr->a[0] -= state_ptr->a[0] >> 8;
+ if (dqsez != 0) {
+ if (pks1 == 0)
+ state_ptr->a[0] += 192;
+ else
+ state_ptr->a[0] -= 192;
+ }
+
+ /* LIMD */
+ a1ul = 15360 - a2p;
+ if (state_ptr->a[0] < -a1ul)
+ state_ptr->a[0] = -a1ul;
+ else if (state_ptr->a[0] > a1ul)
+ state_ptr->a[0] = a1ul;
+
+ /* UPB : update predictor zeros b[6] */
+ for (cnt = 0; cnt < 6; cnt++) {
+ if (code_size == 5) /* for 40Kbps G.723 */
+ state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;
+ else /* for G.721 and 24Kbps G.723 */
+ state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
+ if (dq & 0x7FFF) { /* XOR */
+ if ((dq ^ state_ptr->dq[cnt]) >= 0)
+ state_ptr->b[cnt] += 128;
+ else
+ state_ptr->b[cnt] -= 128;
+ }
+ }
+ }
+
+ for (cnt = 5; cnt > 0; cnt--)
+ state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
+ /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
+ if (mag == 0) {
+ state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;
+ } else {
+ exp = quan(mag, power2, 15);
+ state_ptr->dq[0] = (dq >= 0) ?
+ (exp << 6) + ((mag << 6) >> exp) :
+ (exp << 6) + ((mag << 6) >> exp) - 0x400;
+ }
+
+ state_ptr->sr[1] = state_ptr->sr[0];
+ /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
+ if (sr == 0) {
+ state_ptr->sr[0] = 0x20;
+ } else if (sr > 0) {
+ exp = quan(sr, power2, 15);
+ state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
+ } else if (sr > -32768) {
+ mag = -sr;
+ exp = quan(mag, power2, 15);
+ state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;
+ } else
+ state_ptr->sr[0] = 0xFC20;
+
+ /* DELAY A */
+ state_ptr->pk[1] = state_ptr->pk[0];
+ state_ptr->pk[0] = pk0;
+
+ /* TONE */
+ if (tr == 1) /* this sample has been treated as data */
+ state_ptr->td = 0; /* next one will be treated as voice */
+ else if (a2p < -11776) /* small sample-to-sample correlation */
+ state_ptr->td = 1; /* signal may be data */
+ else /* signal is voice */
+ state_ptr->td = 0;
+
+ /*
+ * Adaptation speed control.
+ */
+ state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */
+ state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
+
+ if (tr == 1)
+ state_ptr->ap = 256;
+ else if (y < 1536) /* SUBTC */
+ state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+ else if (state_ptr->td == 1)
+ state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+ else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
+ (state_ptr->dml >> 3))
+ state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+ else
+ state_ptr->ap += (-state_ptr->ap) >> 4;
+}
+
+/*
+ * tandem_adjust(sr, se, y, i, sign)
+ *
+ * At the end of ADPCM decoding, it simulates an encoder which may be receiving
+ * the output of this decoder as a tandem process. If the output of the
+ * simulated encoder differs from the input to this decoder, the decoder output
+ * is adjusted by one level of A-law or u-law codes.
+ *
+ * Input:
+ * sr decoder output linear PCM sample,
+ * se predictor estimate sample,
+ * y quantizer step size,
+ * i decoder input code,
+ * sign sign bit of code i
+ *
+ * Return:
+ * adjusted A-law or u-law compressed sample.
+ */
+int
+tandem_adjust_alaw(
+ int sr, /* decoder output linear PCM sample */
+ int se, /* predictor estimate sample */
+ int y, /* quantizer step size */
+ int i, /* decoder input code */
+ int sign,
+ short *qtab)
+{
+ unsigned char sp; /* A-law compressed 8-bit code */
+ short dx; /* prediction error */
+ char id; /* quantized prediction error */
+ int sd; /* adjusted A-law decoded sample value */
+ int im; /* biased magnitude of i */
+ int imx; /* biased magnitude of id */
+
+ if (sr <= -32768)
+ sr = -1;
+ sp = linear2alaw((sr >> 1) << 3); /* short to A-law compression */
+ dx = (alaw2linear(sp) >> 2) - se; /* 16-bit prediction error */
+ id = quantize(dx, y, qtab, sign - 1);
+
+ if (id == i) { /* no adjustment on sp */
+ return (sp);
+ } else { /* sp adjustment needed */
+ /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
+ im = i ^ sign; /* 2's complement to biased unsigned */
+ imx = id ^ sign;
+
+ if (imx > im) { /* sp adjusted to next lower value */
+ if (sp & 0x80) {
+ sd = (sp == 0xD5) ? 0x55 :
+ ((sp ^ 0x55) - 1) ^ 0x55;
+ } else {
+ sd = (sp == 0x2A) ? 0x2A :
+ ((sp ^ 0x55) + 1) ^ 0x55;
+ }
+ } else { /* sp adjusted to next higher value */
+ if (sp & 0x80)
+ sd = (sp == 0xAA) ? 0xAA :
+ ((sp ^ 0x55) + 1) ^ 0x55;
+ else
+ sd = (sp == 0x55) ? 0xD5 :
+ ((sp ^ 0x55) - 1) ^ 0x55;
+ }
+ return (sd);
+ }
+}
+
+int
+tandem_adjust_ulaw(
+ int sr, /* decoder output linear PCM sample */
+ int se, /* predictor estimate sample */
+ int y, /* quantizer step size */
+ int i, /* decoder input code */
+ int sign,
+ short *qtab)
+{
+ unsigned char sp; /* u-law compressed 8-bit code */
+ short dx; /* prediction error */
+ char id; /* quantized prediction error */
+ int sd; /* adjusted u-law decoded sample value */
+ int im; /* biased magnitude of i */
+ int imx; /* biased magnitude of id */
+
+ if (sr <= -32768)
+ sr = 0;
+ sp = linear2ulaw(sr << 2); /* short to u-law compression */
+ dx = (ulaw2linear(sp) >> 2) - se; /* 16-bit prediction error */
+ id = quantize(dx, y, qtab, sign - 1);
+ if (id == i) {
+ return (sp);
+ } else {
+ /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
+ im = i ^ sign; /* 2's complement to biased unsigned */
+ imx = id ^ sign;
+ if (imx > im) { /* sp adjusted to next lower value */
+ if (sp & 0x80)
+ sd = (sp == 0xFF) ? 0x7E : sp + 1;
+ else
+ sd = (sp == 0) ? 0 : sp - 1;
+
+ } else { /* sp adjusted to next higher value */
+ if (sp & 0x80)
+ sd = (sp == 0x80) ? 0x80 : sp - 1;
+ else
+ sd = (sp == 0x7F) ? 0xFE : sp + 1;
+ }
+ return (sd);
+ }
+}
diff --git a/src/ccitt-adpcm/g72x.h b/src/ccitt-adpcm/g72x.h
new file mode 100644
index 0000000..3426176
--- /dev/null
+++ b/src/ccitt-adpcm/g72x.h
@@ -0,0 +1,148 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g72x.h
+ *
+ * Header file for CCITT conversion routines.
+ *
+ */
+#ifndef _G72X_H
+#define _G72X_H
+
+#define AUDIO_ENCODING_ULAW (1) /* ISDN u-law */
+#define AUDIO_ENCODING_ALAW (2) /* ISDN A-law */
+#define AUDIO_ENCODING_LINEAR (3) /* PCM 2's-complement (0-center) */
+
+/*
+ * The following is the definition of the state structure
+ * used by the G.721/G.723 encoder and decoder to preserve their internal
+ * state between successive calls. The meanings of the majority
+ * of the state structure fields are explained in detail in the
+ * CCITT Recommendation G.721. The field names are essentially indentical
+ * to variable names in the bit level description of the coding algorithm
+ * included in this Recommendation.
+ */
+struct g72x_state {
+ long yl; /* Locked or steady state step size multiplier. */
+ short yu; /* Unlocked or non-steady state step size multiplier. */
+ short dms; /* Short term energy estimate. */
+ short dml; /* Long term energy estimate. */
+ short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */
+
+ short a[2]; /* Coefficients of pole portion of prediction filter. */
+ short b[6]; /* Coefficients of zero portion of prediction filter. */
+ short pk[2]; /*
+ * Signs of previous two samples of a partially
+ * reconstructed signal.
+ */
+ short dq[6]; /*
+ * Previous 6 samples of the quantized difference
+ * signal represented in an internal floating point
+ * format.
+ */
+ short sr[2]; /*
+ * Previous 2 samples of the quantized difference
+ * signal represented in an internal floating point
+ * format.
+ */
+ char td; /* delayed tone detect, new in 1988 version */
+};
+
+/* External function definitions. */
+
+extern void g72x_init_state(struct g72x_state *);
+extern int predictor_zero(struct g72x_state *state_ptr);
+extern int predictor_pole(struct g72x_state *state_ptr);
+extern int step_size(struct g72x_state *state_ptr);
+
+extern int quantize(
+ int d,
+ int y,
+ short *table,
+ int size);
+extern int reconstruct(
+ int sign,
+ int dqln,
+ int y);
+extern void update(
+ int code_size,
+ int y,
+ int wi,
+ int fi,
+ int dq,
+ int sr,
+ int dqsez,
+ struct g72x_state *state_ptr);
+
+extern int tandem_adjust_alaw(
+ int sr,
+ int se,
+ int y,
+ int i,
+ int sign,
+ short *qtab);
+extern int tandem_adjust_ulaw(
+ int sr,
+ int se,
+ int y,
+ int i,
+ int sign,
+ short *qtab);
+
+extern int g721_encoder(
+ int sample,
+ int in_coding,
+ struct g72x_state *state_ptr);
+extern int g721_decoder(
+ int code,
+ int out_coding,
+ struct g72x_state *state_ptr);
+extern int g723_24_encoder(
+ int sample,
+ int in_coding,
+ struct g72x_state *state_ptr);
+extern int g723_24_decoder(
+ int code,
+ int out_coding,
+ struct g72x_state *state_ptr);
+extern int g723_40_encoder(
+ int sample,
+ int in_coding,
+ struct g72x_state *state_ptr);
+extern int g723_40_decoder(
+ int code,
+ int out_coding,
+ struct g72x_state *state_ptr);
+
+extern unsigned char linear2alaw(int pcm_val);
+extern int alaw2linear(unsigned char a_val);
+extern unsigned char linear2ulaw(int pcm_val);
+extern int ulaw2linear(unsigned char u_val);
+extern unsigned char alaw2ulaw(unsigned char aval);
+extern unsigned char ulaw2alaw(unsigned char uval);
+
+#endif /* !_G72X_H */
diff --git a/src/cli.c b/src/cli.c
new file mode 100644
index 0000000..3b79bc4
--- /dev/null
+++ b/src/cli.c
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <dectmon.h>
+#include <cli.h>
+
+#define DECTMON_HISTFILE ".dectmon_history"
+
+static struct event cli_event;
+static char histfile[PATH_MAX];
+static struct parser_state state;
+static void *scanner;
+
+void cli_display(const char *fmt, va_list ap)
+{
+ int point, end;
+
+ point = rl_point;
+ end = rl_end;
+ rl_point = rl_end = 0;
+ rl_save_prompt();
+ rl_clear_message();
+
+ vfprintf(rl_outstream, fmt, ap);
+
+ rl_restore_prompt();
+ rl_point = point;
+ rl_end = end;
+ rl_forced_update_display();
+}
+
+static void cli_read_callback(int fd, short mask, void *data)
+{
+ rl_callback_read_char();
+}
+
+static void cli_complete(char *line)
+{
+ HIST_ENTRY *hist;
+ char *c;
+
+ if (line == NULL)
+ return;
+
+ /* avoid empty lines in history */
+ for (c = line; c != '\0'; c++) {
+ if (!isspace(*c))
+ break;
+ }
+ if (*c == '\0')
+ return;
+
+ /* avoid duplicate lines in history */
+ hist = history_get(where_history());
+ if (hist == NULL ||
+ ((where_history() != history_length - 1) ||
+ strcmp(hist->line, line)))
+ add_history(line);
+
+ rl_replace_line("", 1);
+ scanner_push_buffer(scanner, line);
+ yyparse(scanner, &state);
+ rl_crlf();
+ free(line);
+}
+
+static const char *keywords[] = {
+ "debug",
+ "cluster",
+ "portable",
+ "tbc",
+ "show",
+ "set",
+ "on",
+ "off",
+ "lce",
+ "cc",
+ "ss",
+ "mm",
+ "clms",
+ "llme",
+ "MNCC_SETUP-req",
+ "MNCC_INFO-req",
+ "sending-complete",
+ "keypad",
+ "basic-service",
+ "escape-to-proprietary",
+ "info",
+ "service",
+ "class",
+ "LIA",
+ "message",
+ "dect/isdn",
+ "normal",
+ "internal",
+ "emergency",
+ "external-handover",
+ "QA&M",
+ "basic-speech",
+ "GSM",
+ "UMTS",
+ "LRMS",
+ "GSM-SMS",
+ "wideband-speech",
+ "SUOTA-class-4",
+ "SUOTA-class-3",
+ "other",
+ "emc",
+ "content",
+ NULL
+};
+
+static char *cli_command_generator(const char *text, int state)
+{
+ static unsigned int idx, len;
+ const char *name;
+
+ if (state == 0) {
+ idx = 0;
+ len = strlen(text);
+ }
+
+ while ((name = keywords[idx]) != NULL) {
+ idx++;
+ if (!strncasecmp(name, text, len))
+ return strdup(name);
+ }
+ return NULL;
+}
+
+static char **cli_completion(const char *text, int start, int end)
+{
+ return rl_completion_matches(text, cli_command_generator);
+}
+
+int cli_init(FILE *file)
+{
+ const char *prompt = NULL;
+ const char *home;
+ int fd;
+
+ parser_init(&state);
+ scanner = scanner_init(&state);
+
+ rl_instream = file;
+ fd = fileno(rl_instream);
+ rl_readline_name = "dectmon";
+ if (isatty(fd))
+ prompt = "dectmon > ";
+
+ rl_outstream = stdout;
+
+ rl_callback_handler_install(prompt, cli_complete);
+ rl_attempted_completion_function = cli_completion;
+
+ home = getenv("HOME");
+ if (home == NULL)
+ home = ".";
+ snprintf(histfile, sizeof(histfile), "%s/%s", home, DECTMON_HISTFILE);
+ read_history(histfile);
+ history_set_pos(history_length);
+
+ event_set(&cli_event, fd, EV_READ | EV_PERSIST, cli_read_callback, NULL);
+ event_add(&cli_event, NULL);
+
+ return 0;
+}
+
+void cli_exit(void)
+{
+ rl_callback_handler_remove();
+ rl_deprep_terminal();
+ write_history(histfile);
+}
diff --git a/src/cmd-parser.y b/src/cmd-parser.y
new file mode 100644
index 0000000..0211371
--- /dev/null
+++ b/src/cmd-parser.y
@@ -0,0 +1,472 @@
+%{
+
+#include <stdint.h>
+#include <dect/libdect.h>
+#include <dectmon.h>
+#include <cli.h>
+
+#include "cmd-parser.h"
+#include "cmd-scanner.h"
+
+static void yyerror(struct location *loc, void *scanner,
+ struct parser_state *state, const char *s)
+{
+ unsigned int plen = strlen("dectmon > ");
+ unsigned int i;
+ char buf[256];
+
+ memset(buf, ' ', sizeof(buf));
+ for (i = loc->first_column - 1 + plen; i < loc->last_column + plen; i++)
+ buf[i] = '^';
+ buf[i] = '\0';
+ dectmon_log("%s\n", buf);
+ dectmon_log("%s\n", s);
+}
+
+static struct dect_handle *parser_get_handle(void)
+{
+ struct dect_handle_priv *priv;
+
+ priv = list_first_entry(&dect_handles, struct dect_handle_priv, list);
+ return priv->dh;
+}
+
+void parser_init(struct parser_state *state)
+{
+ memset(state, 0, sizeof(*state));
+}
+
+static void location_init(void *scanner, struct parser_state *state,
+ struct location *loc)
+{
+ memset(loc, 0, sizeof(*loc));
+}
+
+static void location_update(struct location *loc, struct location *rhs, int n)
+{
+ if (n) {
+ loc->token_offset = rhs[1].token_offset;
+ loc->line_offset = rhs[1].line_offset;
+ loc->first_line = rhs[1].first_line;
+ loc->first_column = rhs[1].first_column;
+ loc->last_line = rhs[n].last_line;
+ loc->last_column = rhs[n].last_column;
+ } else {
+ loc->token_offset = rhs[0].token_offset;
+ loc->line_offset = rhs[0].line_offset;
+ loc->first_line = rhs[0].last_line;
+ loc->last_line = rhs[0].last_line;
+ loc->first_column = rhs[0].last_column;
+ loc->last_column = rhs[0].last_column;
+ }
+}
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) location_update(&Current, Rhs, N)
+
+%}
+
+/* Declarations */
+
+%pure-parser
+%error-verbose
+%parse-param { void *scanner }
+%parse-param { struct parser_state *state }
+%lex-param { scanner }
+%locations
+
+%initial-action {
+ location_init(scanner, state, &yylloc);
+}
+
+%union {
+ uint64_t val;
+ const char *string;
+ struct dect_ie_common *ie;
+ struct dect_mncc_setup_param *mncc_setup_param;
+ struct dect_mncc_info_param *mncc_info_param;
+}
+
+%token TOKEN_EOF 0 "end of file"
+%token JUNK "junk"
+%token NEWLINE "newline"
+
+%token <string> STRING "string"
+%token <val> NUMBER "number"
+
+%token TOK_DEBUG "debug"
+%token CLUSTER "cluster"
+%token PORTABLE "portable"
+%token TBC "tbc"
+
+%token SHOW "show"
+%token SET "set"
+
+%token ON "on"
+%token OFF "off"
+
+%token LCE "lce"
+%token CC "cc"
+%token SS "ss"
+%token CLMS "clms"
+%token MM "mm"
+%token LLME "llme"
+
+%token MNCC_SETUP_REQ "MNCC_SETUP-req"
+%token MNCC_INFO_REQ "MNCC_INFO-req"
+
+%token SENDING_COMPLETE "sending-complete"
+%token KEYPAD "keypad"
+%token BASIC_SERVICE "basic-service"
+%token ESCAPE_TO_PROPRIETARY "escape-to-proprietary"
+
+%token INFO "info"
+%token SERVICE "service"
+%token CLASS "class"
+
+%token LIA "LIA"
+%token MESSAGE "message"
+%token DECT_ISDN "dect/isdn"
+%token NORMAL "normal"
+%token INTERNAL "internal"
+%token EMERGENCY "emergency"
+%token EXTERNAL_HO "external-handover"
+%token QA_M "QA&M"
+
+%token BASIC_SPEECH "basic-speech"
+%token GSM "GSM"
+%token UMTS "UMTS"
+%token LRMS "LRMS"
+%token GSM_SMS "GSM-SMS"
+%token WIDEBAND_SPEECH "wideband-speech"
+%token SUOTA_CLASS_4 "SUOTA-class-4"
+%token SUOTA_CLASS_3 "SUOTA-class-3"
+%token OTHER "other"
+
+%token EMC "EMC"
+%token CONTENT "content"
+
+%type <val> debug_subsys on_off
+
+%type <mncc_setup_param> mncc_setup_param_alloc
+%type <mncc_setup_param> mncc_setup_params mncc_setup_param
+
+%type <mncc_info_param> mncc_info_param_alloc
+%type <mncc_info_param> mncc_info_params mncc_info_param
+
+%type <ie> keypad_ie keypad_ie_alloc
+
+%type <ie> sending_complete_ie
+
+%type <ie> basic_service_ie basic_service_ie_alloc
+%type <ie> basic_service_ie_params basic_service_ie_param
+%type <val> basic_service_ie_class basic_service_ie_service
+
+%type <ie> etp_ie etp_ie_alloc
+%type <ie> etp_ie_params etp_ie_param
+
+%%
+
+input : /* empty */
+ | input line
+ ;
+
+line : cluster_stmt
+ | portable_stmt
+ | tbc_stmt
+ | debug_stmt
+ | cc_primitive
+ ;
+
+cluster_stmt : CLUSTER SHOW
+ {
+ struct dect_handle_priv *priv;
+
+ dectmon_log("Cluster\t\tLocked\t\tPARI\n");
+ list_for_each_entry(priv, &dect_handles, list) {
+ dectmon_log("%s\t%s\t\tEMC: %.4x FPN: %.5x\n",
+ priv->cluster, priv->locked ? "Yes" : "No",
+ priv->pari.emc, priv->pari.fpn);
+ }
+ }
+ ;
+
+portable_stmt : PORTABLE SHOW
+ {
+ char ipei[DECT_IPEI_STRING_LEN];
+ struct dect_handle_priv *priv;
+ struct dect_pt *pt;
+
+ dectmon_log("Cluster\t\tIPEI\n");
+ list_for_each_entry(priv, &dect_handles, list) {
+ list_for_each_entry(pt, &priv->pt_list, list) {
+ dect_format_ipei_string(&pt->portable_identity->ipui.pun.n.ipei,
+ ipei);
+ dectmon_log("%s\t%s\n", priv->cluster, ipei);
+ }
+ }
+ }
+ ;
+
+tbc_stmt : TBC SHOW
+ {
+ struct dect_handle_priv *priv;
+ struct dect_tbc *tbc;
+ unsigned int i;
+
+ dectmon_log("Cluster\t\tPMID\tFMID\tSlots\tCiphered\n");
+ list_for_each_entry(priv, &dect_handles, list) {
+ for (i = 0; i < DECT_HALF_FRAME_SIZE; i++) {
+ tbc = priv->slots[i];
+ if (tbc == NULL)
+ continue;
+ dectmon_log("%s\t%.5x\t%.3x\t%u/%u\t%s\n",
+ priv->cluster,
+ tbc->pmid, tbc->fmid,
+ tbc->slot1, tbc->slot2,
+ tbc->ciphered ? "Yes" : "No");
+ }
+ }
+ }
+ ;
+
+debug_stmt : TOK_DEBUG SET debug_subsys on_off
+ {
+ if ($4)
+ debug_mask |= (1 << $3);
+ else
+ debug_mask &= ~(1 << $3);
+ }
+ ;
+
+debug_subsys : LCE { $$ = DECT_DEBUG_LCE; }
+ | CC { $$ = DECT_DEBUG_CC; }
+ | SS { $$ = DECT_DEBUG_SS; }
+ | CLMS { $$ = DECT_DEBUG_CLMS; }
+ | MM { $$ = DECT_DEBUG_MM; }
+ | LLME { $$ = DECT_DEBUG_NL; }
+ ;
+
+on_off : ON { $$ = true; }
+ | OFF { $$ = false; }
+ ;
+
+cc_primitive : mncc_setup_req
+ | mncc_info_req
+ ;
+
+/*
+ * MNCC_SETUP-req
+ */
+
+mncc_setup_req : MNCC_SETUP_REQ mncc_setup_param_alloc '(' mncc_setup_params ')'
+ {
+ struct dect_handle *dh = parser_get_handle();
+ struct dect_ipui ipui = {};
+ struct dect_call *call;
+
+ call = dect_call_alloc(dh);
+ dect_mncc_setup_req(dh, call, &ipui, $2);
+ }
+
+mncc_setup_param_alloc :
+ {
+ $$ = dect_ie_collection_alloc(parser_get_handle(),
+ sizeof(struct dect_mncc_setup_param));
+ }
+ ;
+
+mncc_setup_params : mncc_setup_param
+ {
+ $$ = $<mncc_setup_param>-1;
+ }
+ | mncc_setup_params ',' mncc_setup_param
+ ;
+
+mncc_setup_param : keypad_ie
+ {
+ $<mncc_setup_param>-1->keypad = (struct dect_ie_keypad *)$1;
+ }
+ | sending_complete_ie
+ {
+ $<mncc_setup_param>-1->sending_complete = (struct dect_ie_sending_complete *)$1;
+ }
+ | basic_service_ie
+ {
+ $<mncc_setup_param>-1->basic_service = (struct dect_ie_basic_service *)$1;
+ }
+ | etp_ie
+ {
+ $<mncc_setup_param>-1->escape_to_proprietary = (struct dect_ie_escape_to_proprietary *)$1;
+ }
+ ;
+
+/*
+ * MNCC_INFO-req
+ */
+
+mncc_info_req : MNCC_INFO_REQ mncc_info_param_alloc '(' mncc_info_params ')'
+ {
+ }
+ ;
+
+mncc_info_param_alloc :
+ {
+ $$ = dect_ie_collection_alloc(parser_get_handle(),
+ sizeof(struct dect_mncc_info_param));
+ }
+ ;
+
+mncc_info_params : mncc_info_param
+ {
+ $$ = $<mncc_info_param>-1;
+ }
+ | mncc_info_params ',' mncc_info_param
+ ;
+
+mncc_info_param : keypad_ie
+ {
+ $<mncc_info_param>-1->keypad = (struct dect_ie_keypad *)$1;
+ }
+ | sending_complete_ie
+ {
+ $<mncc_info_param>-1->sending_complete = (struct dect_ie_sending_complete *)$1;
+ }
+ | etp_ie
+ {
+ $<mncc_info_param>-1->escape_to_proprietary = (struct dect_ie_escape_to_proprietary *)$1;
+ }
+ ;
+
+/*
+ * Keypad IE
+ */
+
+keypad_ie : KEYPAD keypad_ie_alloc '(' keypad_ie_param ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+keypad_ie_alloc :
+ {
+ $$ = dect_ie_alloc(parser_get_handle(), sizeof(struct dect_ie_keypad));
+ }
+
+keypad_ie_param : INFO '=' STRING
+ {
+ struct dect_ie_keypad *ie = dect_ie_container(ie, $<ie>-1);
+
+ ie->len = strlen($3);
+ memcpy(ie->info, $3, ie->len);
+ }
+ ;
+
+/*
+ * Sending complete IE
+ */
+
+sending_complete_ie : SENDING_COMPLETE
+ {
+ $$ = dect_ie_alloc(parser_get_handle(), sizeof(struct dect_ie_sending_complete));
+ }
+ ;
+
+/*
+ * Basic Service IE
+ */
+
+basic_service_ie : BASIC_SERVICE basic_service_ie_alloc '(' basic_service_ie_params ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+basic_service_ie_alloc :
+ {
+ $$ = dect_ie_alloc(parser_get_handle(), sizeof(struct dect_ie_basic_service));
+ }
+ ;
+
+basic_service_ie_params : basic_service_ie_param
+ {
+ $$ = $<ie>-1;
+ }
+ | basic_service_ie_params ',' basic_service_ie_param
+ ;
+
+basic_service_ie_param : CLASS '=' basic_service_ie_class
+ {
+ struct dect_ie_basic_service *ie = dect_ie_container(ie, $<ie>-1);
+
+ ie->class = $3;
+ }
+ | SERVICE '=' basic_service_ie_service
+ {
+ struct dect_ie_basic_service *ie = dect_ie_container(ie, $<ie>-1);
+
+ ie->service = $3;
+ }
+ ;
+
+basic_service_ie_class : LIA { $$ = DECT_CALL_CLASS_LIA_SERVICE_SETUP; }
+ | MESSAGE { $$ = DECT_CALL_CLASS_MESSAGE; }
+ | DECT_ISDN { $$ = DECT_CALL_CLASS_DECT_ISDN; }
+ | NORMAL { $$ = DECT_CALL_CLASS_NORMAL; }
+ | INTERNAL { $$ = DECT_CALL_CLASS_INTERNAL; }
+ | EMERGENCY { $$ = DECT_CALL_CLASS_EMERGENCY; }
+ | SERVICE { $$ = DECT_CALL_CLASS_SERVICE; }
+ | EXTERNAL_HO { $$ = DECT_CALL_CLASS_EXTERNAL_HO; }
+ | SS { $$ = DECT_CALL_CLASS_SUPPLEMENTARY_SERVICE; }
+ | QA_M { $$ = DECT_CALL_CLASS_QA_M; }
+ ;
+
+basic_service_ie_service: BASIC_SPEECH { $$ = DECT_SERVICE_BASIC_SPEECH_DEFAULT; }
+ | GSM { $$ = DECT_SERVICE_DECT_GSM_IWP; }
+ | UMTS { $$ = DECT_SERVICE_UMTS_IWP; }
+ | LRMS { $$ = DECT_SERVICE_LRMS; }
+ | GSM_SMS { $$ = DECT_SERVICE_GSM_IWP_SMS; }
+ | WIDEBAND_SPEECH { $$ = DECT_SERVICE_WIDEBAND_SPEECH; }
+ | SUOTA_CLASS_4 { $$ = DECT_SERVICE_SUOTA_CLASS_4_DPRS_MANAGEMENT; }
+ | SUOTA_CLASS_3 { $$ = DECT_SERVICE_SUOTA_CLASS_3_DPRS_MANAGEMENT; }
+ | OTHER { $$ = DECT_SERVICE_OTHER; }
+ ;
+
+/*
+ * Escape-to-proprietary IE
+ */
+
+etp_ie : ESCAPE_TO_PROPRIETARY etp_ie_alloc '(' etp_ie_params ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+etp_ie_alloc :
+ {
+ $$ = dect_ie_alloc(parser_get_handle(), sizeof(struct dect_ie_escape_to_proprietary));
+ }
+ ;
+
+etp_ie_params : etp_ie_param
+ {
+ $$ = $<ie>-1;
+ }
+ | etp_ie_params ',' etp_ie_param
+ ;
+
+etp_ie_param : EMC '=' NUMBER
+ {
+ struct dect_ie_escape_to_proprietary *ie = dect_ie_container(ie, $<ie>-1);
+
+ ie->emc = $3;
+ }
+ | CONTENT '=' STRING
+ {
+ struct dect_ie_escape_to_proprietary *ie = dect_ie_container(ie, $<ie>-1);
+
+ ie->len = strlen($3);
+ memcpy(ie->content, $3, ie->len);
+ }
+ ;
+
+%%
diff --git a/src/cmd-scanner.l b/src/cmd-scanner.l
new file mode 100644
index 0000000..b32c898
--- /dev/null
+++ b/src/cmd-scanner.l
@@ -0,0 +1,182 @@
+%{
+
+#include <stdint.h>
+#include <cli.h>
+#include "cmd-parser.h"
+
+static void init_pos(struct parser_state *state)
+{
+ state->lineno = 1;
+ state->column = 1;
+ state->token_offset = 0;
+ state->line_offset = 0;
+}
+
+static void update_pos(struct parser_state *state, struct location *loc,
+ int len)
+{
+ loc->first_line = state->lineno;
+ loc->first_column = state->column;
+ loc->last_column = state->column + len - 1;
+ state->column += len;
+}
+
+static void update_offset(struct parser_state *state, struct location *loc,
+ unsigned int len)
+{
+ state->token_offset += len;
+ loc->token_offset = state->token_offset;
+ loc->line_offset = state->line_offset;
+}
+
+static void reset_pos(struct parser_state *state, struct location *loc)
+{
+ state->line_offset = state->token_offset;
+ state->lineno += 1;
+ state->column = 1;
+ loc->line_offset = state->line_offset;
+}
+
+#define YY_USER_ACTION { \
+ update_pos(yyget_extra(yyscanner), yylloc, yyleng); \
+ update_offset(yyget_extra(yyscanner), yylloc, yyleng); \
+}
+
+/* avoid warnings with -Wmissing-prototypes */
+extern int yyget_column(yyscan_t);
+extern void yyset_column(int, yyscan_t);
+
+%}
+
+%option reentrant
+%option noyywrap
+%option nounput
+%option bison-bridge
+%option bison-locations
+%option debug
+%option yylineno
+%option nodefault
+%option warn
+%option case-insensitive
+
+space [ ]
+tab \t
+newline \n
+digit [0-9]
+hexdigit [0-9a-fA-F]
+decstring {digit}+
+hexstring 0[xX]{hexdigit}+
+range ({decstring}?:{decstring}?)
+letter [a-zA-Z]
+string ({letter})({letter}|{digit}|[/\-_\.])*
+quotedstring \"[^"]*\"
+comment #.*$
+slash \/
+%%
+
+"(" { return '('; }
+")" { return ')'; }
+"=" { return '='; }
+"," { return ','; }
+
+"debug" { return TOK_DEBUG; }
+"cluster" { return CLUSTER; }
+"portable" { return PORTABLE; }
+"tbc" { return TBC; }
+
+"show" { return SHOW; }
+"set" { return SET; }
+
+"on" { return ON; }
+"off" { return OFF; }
+
+"lce" { return LCE; }
+"cc" { return CC; }
+"ss" { return SS; }
+"clms" { return CLMS; }
+"mm" { return MM; }
+"llme" { return LLME; }
+
+"MNCC_SETUP-req" { return MNCC_SETUP_REQ; }
+"MNCC_INFO-req" { return MNCC_INFO_REQ; }
+
+"sending-complete" { return SENDING_COMPLETE; }
+"keypad" { return KEYPAD; }
+"basic-service" { return BASIC_SERVICE; }
+"escape-to-proprietary" { return ESCAPE_TO_PROPRIETARY; }
+
+"info" { return INFO; }
+"service" { return SERVICE; }
+"class" { return CLASS; }
+
+"LIA" { return LIA; }
+"message" { return MESSAGE; }
+"dect/isdn" { return DECT_ISDN; }
+"normal" { return NORMAL; }
+"internal" { return INTERNAL; }
+"emergency" { return EMERGENCY; }
+"external-handover" { return EXTERNAL_HO; }
+"QA&M" { return QA_M; }
+
+"basic-speech" { return BASIC_SPEECH; }
+"GSM" { return GSM; }
+"UMTS" { return UMTS; }
+"LRMS" { return LRMS; }
+"GSM-SMS" { return GSM_SMS; }
+"wideband-speech" { return WIDEBAND_SPEECH; }
+"SUOTA-class-4" { return SUOTA_CLASS_4; }
+"SUOTA-class-3" { return SUOTA_CLASS_3; }
+"other" { return OTHER; }
+
+"EMC" { return EMC; }
+"content" { return CONTENT; }
+
+{string} {
+ yylval->string = strdup(yytext);
+ return STRING;
+ }
+
+{decstring} {
+ yylval->val = strtoul(yytext, NULL, 0);
+ return NUMBER;
+ }
+
+\\{newline} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
+
+{newline} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ return NEWLINE;
+ }
+
+{space}+
+
+. { return JUNK; }
+
+%%
+
+void scanner_push_buffer(void *scanner, const char *buffer)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ YY_BUFFER_STATE b;
+
+ b = yy_scan_string(buffer, scanner);
+ init_pos(state);
+}
+
+void *scanner_init(struct parser_state *state)
+{
+ yyscan_t scanner;
+
+ yylex_init(&scanner);
+ yyset_extra(state, scanner);
+ yyset_out(NULL, scanner);
+
+ return scanner;
+}
+
+void scanner_destroy(struct parser_state *scanner)
+{
+ yylex_destroy(scanner);
+}
diff --git a/src/debug.c b/src/debug.c
index 5fd1091..210b2eb 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -36,7 +36,7 @@ void dect_hexdump(const char *prefix, const uint8_t *buf, size_t size)
if (off == BLOCKSIZE - 1 || i == size - 1) {
abuf[off + 1] = '\0';
- printf("%s: %-*s |%s|\n", prefix, 64 - plen, hbuf, abuf);
+ dectmon_log("%s: %-*s |%s|\n", prefix, 64 - plen, hbuf, abuf);
}
}
}
diff --git a/src/dlc.c b/src/dlc.c
index f49a119..d294a39 100644
--- a/src/dlc.c
+++ b/src/dlc.c
@@ -19,7 +19,7 @@
#define dlc_print(fmt, args...) \
do { \
if (dumpopts & DECTMON_DUMP_DLC) \
- printf(fmt, ## args); \
+ dectmon_log(fmt, ## args); \
} while (0)
#if 1
diff --git a/src/mac.c b/src/mac.c
index 14bdae3..513667a 100644
--- a/src/mac.c
+++ b/src/mac.c
@@ -22,7 +22,7 @@
#define mac_print(fmt, args...) \
do { \
if (dumpopts & DECTMON_DUMP_MAC) \
- printf(fmt, ## args); \
+ dectmon_log(fmt, ## args); \
} while (0)
/*
@@ -529,8 +529,8 @@ static int dect_parse_tail_msg(struct dect_tail_msg *tm,
*/
#define tbc_log(tbc, fmt, args...) \
- printf("TBC: PMID: %.5x FMID: %.3x: " fmt, \
- (tbc)->pmid, (tbc)->fmid, ## args)
+ dectmon_log("TBC: PMID: %.5x FMID: %.3x: " fmt, \
+ (tbc)->pmid, (tbc)->fmid, ## args)
static void dect_tbc_release(struct dect_handle *dh, struct dect_tbc *tbc)
{
@@ -682,6 +682,9 @@ static void dect_tbc_rcv(struct dect_handle *dh, struct dect_tbc *tbc,
dect_mbuf_pull(mb, 10);
}
break;
+ case DECT_BI_UTYPE_0:
+ dect_dl_u_data_ind(dh, &tbc->dl, slot < 12, mb);
+ break;
default:
break;
}
@@ -695,7 +698,6 @@ static void dect_tbc_rcv(struct dect_handle *dh, struct dect_tbc *tbc,
case DECT_TM_TYPE_ENCCTRL:
switch (tm->encctl.cmd) {
case DECT_ENCCTRL_START_REQUEST:
- printf("\n");
break;
case DECT_ENCCTRL_START_CONFIRM:
case DECT_ENCCTRL_START_GRANT:
diff --git a/src/main.c b/src/main.c
index 889efe3..1139df1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,18 +14,36 @@
#include <dect/libdect.h>
#include <dect/raw.h>
#include <dectmon.h>
+#include <cli.h>
#define DECT_MAX_CLUSTERS 16
#define DECT_LOCK_TIMEOUT 15
#define cluster_log(priv, fmt, args...) \
- printf("%s: " fmt, \
- ((struct dect_handle_priv *)dect_handle_priv(dh))->cluster, \
- ## args)
+ dectmon_log("%s: " fmt, \
+ ((struct dect_handle_priv *)dect_handle_priv(dh))->cluster, \
+ ## args)
-static LIST_HEAD(dect_handles);
+LIST_HEAD(dect_handles);
static unsigned int locked;
+static FILE *logfile;
+
+void dectmon_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ cli_display(fmt, ap);
+ va_end(ap);
+
+ if (logfile) {
+ va_start(ap, fmt);
+ vfprintf(logfile, fmt, ap);
+ va_end(ap);
+ }
+}
+
static struct dect_handle_priv *dect_handle_lookup(const struct dect_ari *pari)
{
struct dect_handle_priv *priv;
@@ -53,9 +71,6 @@ static void dect_mac_me_info_ind(struct dect_handle *dh,
if (pari != NULL) {
if (dect_handle_lookup(pari) == NULL) {
- cluster_log(dh, "MAC_ME_INFO-ind: EMC: %.4x FPN: %.5x\n",
- pari->emc, pari->fpn);
-
dect_llme_mac_me_info_res(dh, pari);
priv->pari = *pari;
dect_timer_start(dh, priv->lock_timer, DECT_LOCK_TIMEOUT);
@@ -67,6 +82,7 @@ static void dect_mac_me_info_ind(struct dect_handle *dh,
locked, priv->pari.emc, priv->pari.fpn);
dect_timer_stop(dh, priv->lock_timer);
+ priv->locked = true;
}
} else {
locked--;
@@ -74,6 +90,7 @@ static void dect_mac_me_info_ind(struct dect_handle *dh,
locked, priv->pari.emc, priv->pari.fpn);
memset(&priv->pari, 0, sizeof(priv->pari));
+ priv->locked = false;
dect_llme_scan_req(dh);
}
}
@@ -98,6 +115,19 @@ static struct dect_ops ops = {
.raw_ops = &raw_ops,
};
+uint32_t debug_mask = ~0;
+
+static void dect_debug(enum dect_debug_subsys subsys, const char *fmt,
+ va_list ap)
+{
+ char buf[1024];
+
+ if (debug_mask & (1 << subsys)) {
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ dectmon_log("%s", buf);
+ }
+}
+
#define OPTSTRING "c:sm:d:n:p:h"
enum {
@@ -107,6 +137,7 @@ enum {
OPT_DUMP_DLC = 'd',
OPT_DUMP_NWK = 'n',
OPT_AUTH_PIN = 'p',
+ OPT_LOGFILE = 'l',
OPT_HELP = 'h',
};
@@ -117,6 +148,7 @@ static const struct option dectmon_opts[] = {
{ .name = "dump-dlc", .has_arg = true, .flag = 0, .val = OPT_DUMP_DLC, },
{ .name = "dump-nwk", .has_arg = true, .flag = 0, .val = OPT_DUMP_NWK, },
{ .name = "auth-pin", .has_arg = true, .flag = 0, .val = OPT_AUTH_PIN, },
+ { .name = "logfile", .has_arg = true, .flag = 0, .val = OPT_LOGFILE, },
{ .name = "help", .has_arg = false, .flag = 0, .val = OPT_HELP, },
{ },
};
@@ -138,6 +170,7 @@ static void dectmon_help(const char *progname)
" -d/--dump-dlc=yes/no Dump DLC layer messages (default: no)\n"
" -n/--dump-nwk=yes/no Dump NWK layer messages (default: yes)\n"
" -p/--auth-pin=PIN Authentication PIN for Key Allocation\n"
+ " -l/--logfile=NAME Log output to file\n"
" -h/--help Show this help text\n"
"\n",
progname);
@@ -170,6 +203,7 @@ static struct dect_handle *dectmon_open_handle(struct dect_ops *ops,
priv = dect_handle_priv(dh);
priv->cluster = cluster;
+ priv->dh = dh;
priv->lock_timer = dect_timer_alloc(dh);
if (priv->lock_timer == NULL)
@@ -215,6 +249,11 @@ int main(int argc, char **argv)
case OPT_AUTH_PIN:
auth_pin = optarg;
break;
+ case OPT_LOGFILE:
+ logfile = fopen(optarg, "a");
+ if (logfile == NULL)
+ pexit("fopen");
+ break;
case OPT_HELP:
dectmon_help(argv[0]);
exit(0);
@@ -226,6 +265,10 @@ int main(int argc, char **argv)
dect_event_ops_init(&ops);
dect_dummy_ops_init(&ops);
+ dect_audio_init();
+
+ cli_init(stdin);
+ dect_set_debug_hook(dect_debug);
if (ncluster == 0)
ncluster = 1;
@@ -242,5 +285,6 @@ int main(int argc, char **argv)
}
dect_event_loop();
+ cli_exit();
return 0;
}
diff --git a/src/nwk.c b/src/nwk.c
index f1098b2..5569c00 100644
--- a/src/nwk.c
+++ b/src/nwk.c
@@ -200,7 +200,7 @@ static void dect_pt_track_key_allocation(struct dect_handle *dh,
break;
default:
if (pt->procedure == DECT_MM_KEY_ALLOCATION) {
- printf("unexpected message during key allocation\n");
+ dectmon_log("unexpected message during key allocation\n");
goto release;
}
return;
@@ -217,7 +217,7 @@ static void dect_pt_track_key_allocation(struct dect_handle *dh,
dect_auth_a12(ks, pt->rand_f->value, dck, &res1);
if (res1 == pt->res->value) {
- printf("authentication ok\n");
+ dectmon_log("authentication ok\n");
dect_auth_a21(k, pt->rs->value, ks);
@@ -229,7 +229,7 @@ static void dect_pt_track_key_allocation(struct dect_handle *dh,
dect_pt_write_uak(pt);
} else
- printf("authentication failed\n");
+ dectmon_log("authentication failed\n");
release:
dect_ie_release(dh, pt->rs);
@@ -273,7 +273,7 @@ static void dect_pt_track_auth(struct dect_handle *dh,
break;
default:
if (pt->procedure == DECT_MM_AUTHENTICATION) {
- printf("unexpected message during authentication\n");
+ dectmon_log("unexpected message during authentication\n");
goto release;
}
return;
@@ -289,13 +289,13 @@ static void dect_pt_track_auth(struct dect_handle *dh,
dect_auth_a12(ks, pt->rand_f->value, dck, &res1.value);
if (res1.value == pt->res->value) {
- printf("authentication successful\n");
+ dectmon_log("authentication successful\n");
if (pt->auth_type->flags & DECT_AUTH_FLAG_UPC) {
dect_hexdump("DCK", dck, sizeof(dck));
memcpy(pt->dck, dck, sizeof(pt->dck));
}
} else
- printf("authentication failed\n");
+ dectmon_log("authentication failed\n");
release:
dect_ie_release(dh, pt->auth_type);
@@ -321,6 +321,40 @@ static void dect_pt_track_ciphering(struct dect_handle *dh,
}
}
+static void dect_pt_track_audio(struct dect_handle *dh,
+ struct dect_pt *pt, uint8_t msgtype,
+ const struct dect_sfmt_ie *ie,
+ struct dect_ie_common *common)
+{
+ struct dect_ie_progress_indicator *progress_indicator;
+
+ switch (msgtype) {
+ case DECT_CC_SETUP:
+ case DECT_CC_SETUP_ACK:
+ case DECT_CC_CALL_PROC:
+ case DECT_CC_INFO:
+ case DECT_CC_ALERTING:
+ if (ie->id != DECT_IE_PROGRESS_INDICATOR)
+ break;
+ progress_indicator = (void *)common;
+ if (progress_indicator->progress !=
+ DECT_PROGRESS_INBAND_INFORMATION_NOW_AVAILABLE)
+ break;
+ /* fall through */
+ case DECT_CC_CONNECT:
+ if (pt->ah == NULL)
+ pt->ah = dect_audio_open();
+ break;
+ case DECT_CC_RELEASE:
+ case DECT_CC_RELEASE_COM:
+ if (pt->ah != NULL) {
+ dect_audio_close(pt->ah);
+ pt->ah = NULL;
+ }
+ break;
+ }
+}
+
void dect_dl_data_ind(struct dect_handle *dh, struct dect_dl *dl,
struct dect_msg_buf *mb)
{
@@ -334,9 +368,9 @@ void dect_dl_data_ind(struct dect_handle *dh, struct dect_dl *dl,
msgtype = mb->data[1];
- printf("\n");
+ dectmon_log("\n");
dect_hexdump("NWK", mb->data, mb->len);
- printf("{%s} message:\n", nwk_msg_types[msgtype]);
+ dectmon_log("{%s} message:\n", nwk_msg_types[msgtype]);
dect_mbuf_pull(mb, 2);
while (mb->len) {
@@ -357,9 +391,31 @@ void dect_dl_data_ind(struct dect_handle *dh, struct dect_dl *dl,
dect_pt_track_key_allocation(dh, dl->pt, msgtype, &ie, common);
dect_pt_track_auth(dh, dl->pt, msgtype, &ie, common);
dect_pt_track_ciphering(dh, dl->pt, msgtype, &ie, common);
+ dect_pt_track_audio(dh, dl->pt, msgtype, &ie, common);
}
__dect_ie_put(dh, common);
dect_mbuf_pull(mb, ie.len);
}
}
+
+void dect_dl_u_data_ind(struct dect_handle *dh, struct dect_dl *dl, bool dir,
+ struct dect_msg_buf *mb)
+{
+ struct dect_pt *pt = dl->pt;
+ struct dect_msg_buf *clone;
+
+ if (pt == NULL || pt->ah == NULL)
+ return;
+
+ /* Clone message buffer - audio is processed asynchronously, so we can't
+ * use the on-stack buffer
+ */
+ clone = dect_mbuf_alloc(dh);
+ if (clone == NULL)
+ return;
+
+ mb->len = 40;
+ memcpy(dect_mbuf_put(clone, mb->len), mb->data, mb->len);
+ dect_audio_queue(pt->ah, dir, clone);
+}