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:
parent
6629561108
commit
a222b17339
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -1 +1,4 @@
|
|||
cmd-parser.[ch]
|
||||
cmd-scanner.[ch]
|
||||
|
||||
dectmon
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)));
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
10
src/mac.c
10
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:
|
||||
|
|
58
src/main.c
58
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;
|
||||
}
|
||||
|
|
72
src/nwk.c
72
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);
|
||||
}
|
||||
|
|
Reference in New Issue