dect
/
dectmon
Archived
13
0
Fork 0

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>
This commit is contained in:
Patrick McHardy 2010-11-19 19:50:12 +01:00
parent 6629561108
commit a222b17339
25 changed files with 3071 additions and 25 deletions

View File

@ -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

View File

@ -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

37
include/cli.h Normal file
View File

@ -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 */

View File

@ -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_timer *lock_timer;
struct dect_ari pari;
struct list_head pt_list;
struct dect_handle *dh;
struct dect_timer *lock_timer;
bool locked;
struct dect_ari pari;
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 */

76
include/utils.h Normal file
View File

@ -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 */

3
src/.gitignore vendored
View File

@ -1 +1,4 @@
cmd-parser.[ch]
cmd-scanner.[ch]
dectmon

View File

@ -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

120
src/audio.c Normal file
View File

@ -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);
}

94
src/ccitt-adpcm/README Normal file
View File

@ -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

113
src/ccitt-adpcm/decode.c Normal file
View File

@ -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);
}

119
src/ccitt-adpcm/encode.c Normal file
View File

@ -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);
}

285
src/ccitt-adpcm/g711.c Normal file
View File

@ -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)));
}

173
src/ccitt-adpcm/g721.c Normal file
View File

@ -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);
}
}

158
src/ccitt-adpcm/g723_24.c Normal file
View File

@ -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);
}
}

178
src/ccitt-adpcm/g723_40.c Normal file
View File

@ -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);
}
}

565
src/ccitt-adpcm/g72x.c Normal file
View File

@ -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);
}
}

148
src/ccitt-adpcm/g72x.h Normal file
View File

@ -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 */

177
src/cli.c Normal file
View File

@ -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);
}

472
src/cmd-parser.y Normal file
View File

@ -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);
}
;
%%

182
src/cmd-scanner.l Normal file
View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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:

View File

@ -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;
}

View File

@ -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);
}