Compare commits

...

10 Commits

Author SHA1 Message Date
Andreas Eversberg 4ab3db97ab Fixed issue in handling channel offer 7 months ago
Andreas Eversberg 89d0d260b9 ph_driver: Fixed wrong debug output 7 months ago
Andreas Eversberg 67d01841a7 libmisdnuser: Fixed compiler warning 7 months ago
Andreas Eversberg e8c6a82a57 Fixed mISDN (kernel code) to use MPH_ instead of PH_ towards layer 3 8 months ago
Andreas Eversberg 79cd8295c2 fixup libmisdn 8 months ago
Andreas Eversberg 0d74475db1 fixup libmisdnuser 8 months ago
Andreas Eversberg 3672a4c99e Make this application capable of using kernel or user space mISDN 8 months ago
Andreas Eversberg 4150cc3e67 Add mISDNuser to this project 8 months ago
Andreas Eversberg 7ebde07432 Add port of mISDN kernel driver for use in user space 8 months ago
Andreas Eversberg b34219a725 Updated Libs 8 months ago
  1. 2
      .gitignore
  2. 4
      configure.ac
  3. 2
      src/Makefile.am
  4. 9
      src/isdn/Makefile.am
  5. 7
      src/isdn/dss1.c
  6. 226
      src/isdn/isdn.c
  7. 7
      src/isdn/isdn.h
  8. 76
      src/isdn/main.c
  9. 309
      src/isdn/ph_driver.c
  10. 14
      src/isdn/ph_driver.h
  11. 1
      src/isdn/ph_socket.c
  12. 1
      src/isdn/ph_socket.h
  13. 65
      src/libdebug/debug.c
  14. 72
      src/libdebug/debug.h
  15. 17
      src/libmisdn/Makefile.am
  16. 25
      src/libmisdn/bitops.h
  17. 33
      src/libmisdn/container_of.h
  18. 429
      src/libmisdn/core.c
  19. 77
      src/libmisdn/core.h
  20. 177
      src/libmisdn/fsm.c
  21. 59
      src/libmisdn/fsm.h
  22. 523
      src/libmisdn/hwchannel.c
  23. 415
      src/libmisdn/layer1.c
  24. 16
      src/libmisdn/layer1.h
  25. 2266
      src/libmisdn/layer2.c
  26. 130
      src/libmisdn/layer2.h
  27. 192
      src/libmisdn/mISDNhw.h
  28. 656
      src/libmisdn/mISDNif.h
  29. 198
      src/libmisdn/mlist.h
  30. 27
      src/libmisdn/printk.c
  31. 16
      src/libmisdn/printk.h
  32. 241
      src/libmisdn/skbuff.h
  33. 646
      src/libmisdn/socket.c
  34. 14
      src/libmisdn/socket.h
  35. 660
      src/libmisdn/stack.c
  36. 1412
      src/libmisdn/tei.c
  37. 19
      src/libmisdn/timer.h
  38. 23
      src/libmisdnuser/Makefile.am
  39. 57
      src/libmisdnuser/asn1/asn1.c
  40. 173
      src/libmisdnuser/asn1/asn1_enc.c
  41. 234
      src/libmisdnuser/asn1/asn1_generic.c
  42. 26
      src/libmisdnuser/include/3pty.h
  43. 290
      src/libmisdnuser/include/asn1.h
  44. 94
      src/libmisdnuser/include/ccbs.h
  45. 78
      src/libmisdnuser/include/debug.h
  46. 91
      src/libmisdnuser/include/diversion.h
  47. 74
      src/libmisdnuser/include/dss1.h
  48. 47
      src/libmisdnuser/include/ect.h
  49. 63
      src/libmisdnuser/include/fsm.h
  50. 76
      src/libmisdnuser/include/helper.h
  51. 178
      src/libmisdnuser/include/layer3.h
  52. 40
      src/libmisdnuser/include/mISDN/af_isdn.h
  53. 78
      src/libmisdnuser/include/mISDN/l3dss1.h
  54. 5
      src/libmisdnuser/include/mISDN/mISDNcompat.h
  55. 420
      src/libmisdnuser/include/mISDN/mISDNif.h
  56. 259
      src/libmisdnuser/include/mISDN/mbuffer.h
  57. 260
      src/libmisdnuser/include/mISDN/mlayer3.h
  58. 363
      src/libmisdnuser/include/mISDN/q931.h
  59. 1267
      src/libmisdnuser/include/mISDN/suppserv.h
  60. 119
      src/libmisdnuser/include/mlist.h
  61. 46
      src/libmisdnuser/include/mtimer.h
  62. 1904
      src/libmisdnuser/layer3/dss1net.c
  63. 2343
      src/libmisdnuser/layer3/dss1user.c
  64. 1053
      src/libmisdnuser/layer3/layer3.c
  65. 386
      src/libmisdnuser/layer3/mlayer3.c
  66. 1326
      src/libmisdnuser/layer3/q931.c
  67. 162
      src/libmisdnuser/misc/debug.c
  68. 159
      src/libmisdnuser/misc/fsm.c
  69. 457
      src/libmisdnuser/misc/mbuffer.c
  70. 176
      src/libmisdnuser/misc/mtimer.c
  71. 110
      src/libmisdnuser/suppserv/3pty.c
  72. 624
      src/libmisdnuser/suppserv/address.c
  73. 348
      src/libmisdnuser/suppserv/aoc.c
  74. 13
      src/libmisdnuser/suppserv/basic_service.c
  75. 1666
      src/libmisdnuser/suppserv/ccbs.c
  76. 590
      src/libmisdnuser/suppserv/component.c
  77. 1569
      src/libmisdnuser/suppserv/diversion.c
  78. 403
      src/libmisdnuser/suppserv/ect.c
  79. 879
      src/libmisdnuser/suppserv/fac.c
  80. 26
      src/libosmocc/endpoint.c
  81. 605
      src/libosmocc/message.c
  82. 72
      src/libosmocc/message.h
  83. 11
      src/libosmocc/rtp.c
  84. 2
      src/libosmocc/sdp.c
  85. 14
      src/libtimer/timer.c

2
.gitignore vendored

@ -40,4 +40,6 @@ src/liboptions/liboptions.a
src/libosmocc/libosmocc.a
src/libsample/libsample.a
src/libtimer/libtimer.a
src/libmisdn/libmisdn.a
src/libmisdnuser/libmisdnuser.a
src/isdn/osmo-cc-misdn-endpoint

@ -74,7 +74,7 @@ AC_SUBST(SYMBOL_VISIBILITY)
dnl Generate the output
AM_CONFIG_HEADER(config.h)
AC_CHECK_HEADERS([mISDN/mbuffer.h], , [AC_MSG_FAILURE(Missing mISDN user library. Please install mISDNuser!)])
#AC_CHECK_HEADERS([mISDN/mbuffer.h], , [AC_MSG_FAILURE(Missing mISDN user library. Please install mISDNuser!)])
AC_CHECK_LIB([m], [main])
AC_CHECK_LIB([pthread], [main])
@ -87,6 +87,8 @@ AC_OUTPUT(
src/libjitter/Makefile
src/libosmocc/Makefile
src/libg711/Makefile
src/libmisdn/Makefile
src/libmisdnuser/Makefile
src/isdn/Makefile
src/Makefile
Makefile)

@ -8,5 +8,7 @@ SUBDIRS = \
libjitter \
libosmocc \
libg711 \
libmisdn \
libmisdnuser \
isdn

@ -1,4 +1,4 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) -I$(srcdir)/../libmisdnuser/include
bin_PROGRAMS = \
osmo-cc-misdn-endpoint
@ -7,6 +7,8 @@ osmo_cc_misdn_endpoint_SOURCES = \
ie.c \
dss1.c \
isdn.c \
ph_socket.c \
ph_driver.c \
main.c
osmo_cc_misdn_endpoint_LDADD = \
@ -18,5 +20,8 @@ osmo_cc_misdn_endpoint_LDADD = \
../libjitter/libjitter.a \
../libosmocc/libosmocc.a \
../libg711/libg711.a \
-lmisdn
../libmisdn/libmisdn.a \
../libmisdnuser/libmisdnuser.a
# -lmisdn

@ -1516,14 +1516,15 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
PDEBUG(DDSS1, DEBUG_INFO, "Codec %s selected for transmission.\n", call->codec->payload_name);
/* get channel */
rc = hunt_bchannel_out(call->isdn_ep, &call->b_channel, &call->b_exclusive);
rc = hunt_bchannel_out(call->isdn_ep, &channel, &exclusive);
if (rc < 0) {
PDEBUG(DDSS1, DEBUG_NOTICE, "There is no channel available on the interface.\n");
release_and_destroy(call, -rc, 0, 0);
return;
}
channel = call->b_channel;
exclusive = call->b_exclusive;
/* must seize it, if we gave a channel, so that requested channel is stored in call instance */
if (channel)
seize_bchannel(call, channel, exclusive);
/* creating pid */
call->l3_pid = request_new_pid(call->isdn_ep->ml3);

@ -37,6 +37,7 @@
#endif
#include <mISDN/mlayer3.h>
#include <mISDN/q931.h>
#include "../libmisdn/socket.h"
#ifndef container_of
#define container_of(ptr, type, member) ({ \
@ -511,8 +512,8 @@ int open_bchannel_out(call_t *call, unsigned int cmd, int channel, int exclusive
if (channel==-1 || call->b_channel==channel) {
call->b_exclusive = 1; // we are done
/* if channel was accepted, try to get it */
rc = seize_bchannel(call, channel, 1); // exclusively
/* if channel was accepted, seize_bchannel shall simply return, because given channel is already set */
rc = seize_bchannel(call, call->b_channel, 1); // exclusively
if (rc < 0) {
PDEBUG(DISDN, DEBUG_DEBUG, " -> result = replied channel not available\n");
return -47;
@ -531,7 +532,7 @@ int open_bchannel_out(call_t *call, unsigned int cmd, int channel, int exclusive
return -111; // protocol error
}
/* if channel was not accepted, try to get it */
/* if channel was not accepted, try to get a different one */
rc = seize_bchannel(call, channel, 1); // exclusively
if (rc < 0) {
PDEBUG(DISDN, DEBUG_DEBUG, " -> result = replied channel not available\n");
@ -655,16 +656,18 @@ void isdn_destroy(isdn_t *isdn_ep)
{
struct msn_list *msn;
/* destroy all calls */
while (isdn_ep->call_list)
call_destroy(isdn_ep->call_list);
/* remove stack instance */
isdn_close(isdn_ep);
/* close mISDN socket */
if (isdn_ep->socket > 0)
close(isdn_ep->socket);
/* destroy all calls */
while (isdn_ep->call_list)
call_destroy(isdn_ep->call_list);
if (isdn_ep->l2sock)
close(isdn_ep->l2sock);
if (isdn_ep->l2inst)
mISDN_base_release(isdn_ep->l2inst);
/* free msn list */
while (isdn_ep->msn_list) {
@ -683,17 +686,30 @@ void isdn_destroy(isdn_t *isdn_ep)
}
/* initialization and configuration to isdn interface instance */
int isdn_initialize(isdn_t *isdn_ep, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location)
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location)
{
int rc;
void *mui;
/* open mISDN socket */
rc = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Cannot open mISDN due to errno=%d:%s. (Does your Kernel support socket based mISDN? Protocol family is %d.)\n", errno, strerror(errno), PF_ISDN);
return -errno;
if (!ph_socket) {
/* open mISDN socket */
rc = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Cannot open mISDN due to errno=%d:%s. (Does your Kernel support socket based mISDN? Protocol family is %d.)\n", errno, strerror(errno), PF_ISDN);
return -errno;
}
isdn_ep->l2sock = rc;
} else {
isdn_ep->ph_socket = ph_socket;
/* open mISDN user space */
rc = mISDN_base_create(&mui, ISDN_P_BASE);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Cannot open mISDN due to errno=%d:%s. (Please fix!)\n", errno, strerror(errno));
return -errno;
}
isdn_ep->l2inst = mui;
portname = "0";
}
isdn_ep->socket = rc;
/* store settings */
isdn_ep->law = law;
@ -907,37 +923,39 @@ static int bchannel_create(isdn_t *isdn_ep, int index)
memset(&addr, 0, sizeof(addr));
if (isdn_ep->b_sock[index] > 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Socket already created for index %d\n", index);
return -EIO;
}
if (isdn_ep->l2sock) {
if (isdn_ep->b_sock[index] > 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Socket already created for index %d\n", index);
return -EIO;
}
/* open socket */
if (isdn_ep->b_mode[index] == B_MODE_HDLC) {
PDEBUG(DISDN, DEBUG_NOTICE, "Use B-Channel with HDLC l!!!\n");
}
rc = socket(PF_ISDN, SOCK_DGRAM, (isdn_ep->b_mode[index] == B_MODE_HDLC) ? ISDN_P_B_L2DSPHDLC : ISDN_P_B_L2DSP);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index);
return(0);
}
isdn_ep->b_sock[index] = rc;
/* set nonblocking io */
flags = fcntl(isdn_ep->b_sock[index], F_GETFL);
flags |= O_NONBLOCK;
fcntl(isdn_ep->b_sock[index], F_SETFL, flags);
/* bind socket to bchannel */
addr.family = AF_ISDN;
addr.dev = isdn_ep->portnum;
addr.channel = channel;
rc = bind(isdn_ep->b_sock[index], (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", index, errno);
close(isdn_ep->b_sock[index]);
return -errno;
}
/* open socket */
if (isdn_ep->b_mode[index] == B_MODE_HDLC) {
PDEBUG(DISDN, DEBUG_NOTICE, "Use B-Channel with HDLC l!!!\n");
}
rc = socket(PF_ISDN, SOCK_DGRAM, (isdn_ep->b_mode[index] == B_MODE_HDLC) ? ISDN_P_B_L2DSPHDLC : ISDN_P_B_L2DSP);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index);
return(0);
}
isdn_ep->b_sock[index] = rc;
/* set nonblocking io */
flags = fcntl(isdn_ep->b_sock[index], F_GETFL);
flags |= O_NONBLOCK;
fcntl(isdn_ep->b_sock[index], F_SETFL, flags);
/* bind socket to bchannel */
addr.family = AF_ISDN;
addr.dev = isdn_ep->portnum;
addr.channel = channel;
rc = bind(isdn_ep->b_sock[index], (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", index, errno);
close(isdn_ep->b_sock[index]);
return -errno;
}
}
PDEBUG(DISDN, DEBUG_DEBUG, "created socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
@ -951,15 +969,25 @@ static void bchannel_activate(isdn_t *isdn_ep, int index, int activate, int time
int channel = index + 1 + (index >= 15);
int rc;
if (isdn_ep->l2sock) {
if (isdn_ep->b_sock[index] <= 0)
return;
if (isdn_ep->b_sock[index] <= 0)
return;
act.prim = (activate) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ;
act.id = 0;
rc = sendto(isdn_ep->b_sock[index], &act, MISDN_HEADER_LEN, 0, NULL, 0);
if (rc < 0)
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket #%d, of B-channel %d\n", isdn_ep->b_sock[index], channel);
}
act.prim = (activate) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ;
act.id = 0;
rc = sendto(isdn_ep->b_sock[index], &act, MISDN_HEADER_LEN, 0, NULL, 0);
if (rc < 0)
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket #%d, of B-channel %d\n", isdn_ep->b_sock[index], channel);
if (isdn_ep->l2inst) {
uint8_t mode = PH_MODE_TRANS;
if (isdn_ep->b_mode[index] == B_MODE_HDLC) {
PDEBUG(DISDN, DEBUG_NOTICE, "Use B-Channel with HDLC!!!\n");
mode = PH_MODE_HDLC;
}
ph_socket_tx_msg(isdn_ep->ph_socket, channel, (activate) ? PH_PRIM_ACT_REQ : PH_PRIM_DACT_REQ, &mode, 1);
}
PDEBUG(DISDN, DEBUG_DEBUG, "%s B-channel %d%s\n", (activate) ? "activating" : "deactivating", channel, (timeout) ? " after timeout recovery" : "");
@ -1077,13 +1105,19 @@ static void bchannel_destroy(isdn_t *isdn_ep, int index)
{
int channel = index + 1 + (index >= 15);
if (isdn_ep->b_sock[index] <= 0)
return;
if (isdn_ep->l2sock) {
if (isdn_ep->b_sock[index] <= 0)
return;
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
close(isdn_ep->b_sock[index]);
isdn_ep->b_sock[index] = 0;
close(isdn_ep->b_sock[index]);
isdn_ep->b_sock[index] = 0;
}
if (isdn_ep->l2inst) {
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed B-channel %d\n", channel);
}
}
/*
@ -1287,8 +1321,8 @@ void bchannel_event(isdn_t *isdn_ep, int index, int event)
static void bchannel_receive(isdn_t *isdn_ep, int index, struct mISDNhead *hh, unsigned char *data, int len);
/* handle frames from B-channel */
static int bchannel_work(isdn_t *isdn_ep, int index)
/* handle frames from B-channel (kernel socket) */
static int bchannel_kernel_sock_work(isdn_t *isdn_ep, int index)
{
int channel = index + 1 + (index >= 15);
unsigned char buffer[2048+MISDN_HEADER_LEN];
@ -1320,7 +1354,7 @@ static int bchannel_work(isdn_t *isdn_ep, int index)
if (isdn_ep->b_call[index])
bchannel_receive(isdn_ep, index, hh, buffer + MISDN_HEADER_LEN, rc - MISDN_HEADER_LEN);
else
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to an ISDNPort (channel %d), ignoring.\n", channel);
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel);
break;
case PH_ACTIVATE_IND:
@ -1346,6 +1380,34 @@ static int bchannel_work(isdn_t *isdn_ep, int index)
return 1;
}
/* handle data frames from B-channel (ph_socket) */
void bchannel_ph_sock_receive(void *priv, int channel, uint8_t prim, uint8_t *data, int length)
{
isdn_t *isdn_ep = (isdn_t *)priv;
int index = channel - 1 - (channel > 16);
if (index < 0 || index > 127)
return;
switch (prim) {
case PH_PRIM_DATA_IND:
if (isdn_ep->b_call[index]) {
struct mISDNhead hh = { .prim = PH_DATA_IND };
bchannel_receive(isdn_ep, index, &hh, data, length);
} else
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel);
break;
case PH_PRIM_ACT_IND:
PDEBUG(DISDN, DEBUG_DEBUG, "PH_PRIM_ACT_IND: bchannel is now activated (channel %d).\n", channel);
bchannel_event(isdn_ep, index, B_EVENT_ACTIVATED);
break;
case PH_PRIM_DACT_IND:
PDEBUG(DISDN, DEBUG_DEBUG, "PH_PRIM_DACT_IND: bchannel is now deactivated (channel %d).\n", channel);
bchannel_event(isdn_ep, index, B_EVENT_DEACTIVATED);
break;
}
}
static void b_timer_timeout(struct timer *timer)
{
struct b_timer_inst *ti = timer->priv;
@ -1516,11 +1578,14 @@ static void send_to_rtp(call_t *call, unsigned char *data, int len)
if (call->b_index >= 0) {
unsigned char buf[MISDN_HEADER_LEN + len];
struct mISDNhead *frm = (struct mISDNhead *)buf;
int rc;
int rc = 0;
memcpy(buf + MISDN_HEADER_LEN, data, len);
frm->prim = PH_DATA_REQ;
frm->id = 0;
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
if (call->isdn_ep->ph_socket)
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, len);
else
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
if (rc < 0)
PDEBUG(DISDN, DEBUG_ERROR, "write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
}
@ -1629,11 +1694,14 @@ void bchannel_send(struct osmo_cc_session_codec *codec, uint16_t __attribute__((
if (call->b_index >= 0) {
unsigned char buf[MISDN_HEADER_LEN + len];
struct mISDNhead *frm = (struct mISDNhead *)buf;
int rc;
int rc = 0;
memcpy(buf + MISDN_HEADER_LEN, data, len);
frm->prim = PH_DATA_REQ;
frm->id = 0;
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
if (call->isdn_ep->ph_socket)
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, len);
else
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
if (rc < 0)
PDEBUG(DISDN, DEBUG_ERROR, "write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
}
@ -1667,7 +1735,7 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
return 0;
}
int mISDN_getportbyname(int sock, int cnt, const char *portname)
int mISDN_getportbyname(isdn_t *isdn_ep, int cnt, const char *portname)
{
struct mISDN_devinfo devinfo;
int port = 0, rc;
@ -1677,7 +1745,10 @@ int mISDN_getportbyname(int sock, int cnt, const char *portname)
/* resolve name */
while (port < cnt) {
devinfo.id = port;
rc = ioctl(sock, IMGETDEVINFO, &devinfo);
if (isdn_ep->l2sock)
rc = ioctl(isdn_ep->l2sock, IMGETDEVINFO, &devinfo);
if (isdn_ep->l2inst)
rc = mISDN_base_ioctl(isdn_ep->l2inst, IMGETDEVINFO, &devinfo);
if (rc < 0)
return rc;
if (!strcasecmp(devinfo.name, portname))
@ -1706,7 +1777,7 @@ int isdn_open(isdn_t *isdn_ep)
int nt, te;
struct mISDN_devinfo devinfo;
unsigned int protocol, prop;
int rc;
int rc = 0;
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
mqueue_init(&isdn_ep->upqueue);
@ -1725,7 +1796,10 @@ int isdn_open(isdn_t *isdn_ep)
memset(&devinfo, 0, sizeof(devinfo));
/* check port counts */
rc = ioctl(isdn_ep->socket, IMGETCOUNT, &cnt);
if (isdn_ep->l2sock)
rc = ioctl(isdn_ep->l2sock, IMGETCOUNT, &cnt);
if (isdn_ep->l2inst)
rc = mISDN_base_ioctl(isdn_ep->l2inst, IMGETCOUNT, &cnt);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed errno = %d)\n", errno);
goto error;
@ -1736,7 +1810,7 @@ int isdn_open(isdn_t *isdn_ep)
goto error;
}
if (portnum < 0) {
portnum = mISDN_getportbyname(isdn_ep->socket, cnt, portname);
portnum = mISDN_getportbyname(isdn_ep, cnt, portname);
if (portnum < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", portname);
goto error;
@ -1751,7 +1825,10 @@ int isdn_open(isdn_t *isdn_ep)
/* get port attributes */
pri = bri = nt = te = 0;
devinfo.id = portnum;
rc = ioctl(isdn_ep->socket, IMGETDEVINFO, &devinfo);
if (isdn_ep->l2sock)
rc = ioctl(isdn_ep->l2sock, IMGETDEVINFO, &devinfo);
if (isdn_ep->l2inst)
rc = mISDN_base_ioctl(isdn_ep->l2inst, IMGETDEVINFO, &devinfo);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Cannot get device information for port %d. (ioctl IMGETDEVINFO failed errno=%d)\n", portnum, errno);
goto error;
@ -1861,6 +1938,8 @@ int isdn_open(isdn_t *isdn_ep)
}
isdn_ep->b_num = devinfo.nrbchan;
if (!isdn_ep->b_num)
isdn_ep->b_num = (pri) ? 30 : 2;
isdn_ep->portnum = portnum;
if (isdn_ep->portname)
free(isdn_ep->portname);
@ -1888,7 +1967,8 @@ int isdn_open(isdn_t *isdn_ep)
if (isdn_ep->ntmode && !isdn_ep->ptp)
isdn_ep->l2link = 1;
PDEBUG(DISDN, DEBUG_DEBUG, "using 'mISDN_dsp.o' module\n");
if (isdn_ep->l2sock)
PDEBUG(DISDN, DEBUG_DEBUG, "using 'mISDN_dsp.o' module\n");
return 0;
@ -2064,7 +2144,7 @@ void isdn_bchannel_work(isdn_t *isdn_ep)
for (i = 0; i < isdn_ep->b_num; i++) {
do {
if (isdn_ep->b_sock[i] > 0)
w = bchannel_work(isdn_ep, i);
w = bchannel_kernel_sock_work(isdn_ep, i);
else
w = 0;
} while (w);

@ -5,6 +5,7 @@
#include "../libosmocc/helper.h"
#include "../libsample/sample.h"
#include "../libjitter/jitter.h"
#include "ph_socket.h"
#define B_MODE_TRANSPARENT 0
#define B_MODE_HDLC 1
@ -91,7 +92,9 @@ typedef struct isdn {
int pri;
int l1hold;
int l2hold;
int socket;
int l2sock;
void *l2inst;
ph_socket_t *ph_socket;
pthread_mutex_t upqueue_lock;
struct mqueue upqueue;
int upqueue_initialized;
@ -180,7 +183,7 @@ int open_bchannel_out(call_t *call, unsigned int cmd, int channel, int exclusive
/* isdn instance */
isdn_t *isdn_create(void);
void isdn_destroy(isdn_t *isdn_ep);
int isdn_initialize(isdn_t *isdn_ep, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location);
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location);
int isdn_open(isdn_t *isdn_ep);
void isdn_close(isdn_t *isdn_ep);
void isdn_add_msn(isdn_t *isdn_ep, const char *msn);

@ -30,12 +30,15 @@
#include <mISDN/mbuffer.h>
#include "isdn.h"
#include "dss1.h"
#include "../libmisdn/core.h"
#include "ph_driver.h"
isdn_t *isdn_ep = NULL;
int num_kanal = 1;
static char law = 'a';
static const char *portname = "0";
static const char *portname = NULL;
static int misdn_kernel = 0, misdn_user = 0;
static int ntmode = 0;
static int ptp = 0;
static int layer1hold = 0;
@ -68,15 +71,14 @@ static void print_help()
printf(" --config [~/]<path to config file>\n");
printf(" Give a config file to use. If it starts with '~/', path is at home dir.\n");
printf(" Each line in config file is one option, '-' or '--' must not be given!\n");
printf(" -v --verbose <level> | <level>,<category>[,<category>[,...]] | list\n");
printf(" Use 'list' to get a list of all levels and categories\n");
printf(" Verbose level: digit of debug level (default = '%d')\n", debuglevel);
printf(" Verbose level+category: level digit followed by one or more categories\n");
printf(" -> If no category is specified, all categories are selected\n");
debug_print_help();
printf(" --ulaw\n");
printf(" Use U-LAW for b-channel coding instead of alaw.\n");
printf(" -p --port <portnr> | <portname>\n");
printf(" Number or name of misdn port (see misdn_info). (Default = %s)\n", portname);
printf(" Number or name of misdn port (see misdn_info).\n");
printf(" -s --socket <path>\n");
printf(" Path to UNIX socket that provides layer 1 connection to an ISDN\n");
printf(" interface.\n");
printf(" -n --nt\n");
printf(" The given port is configured as NT-mode, instead of TE-mode.\n");
printf(" -0 --ptp\n");
@ -153,6 +155,7 @@ static void add_options(void)
option_add('v', "verbose", 1);
option_add(OPT_ULAW, "ulaw", 0);
option_add('p', "port", 1);
option_add('s', "socket", 1);
option_add('n', "nt", 0);
option_add('0', "ptp", 0);
option_add('M', "msn", 1);
@ -197,6 +200,11 @@ static int handle_options(int short_option, int argi, char **argv)
break;
case 'p':
portname = options_strdup(argv[argi]);
misdn_kernel = 1;
break;
case 's':
portname = options_strdup(argv[argi]);
misdn_user = 1;
break;
case 'n':
ntmode = 1;
@ -299,7 +307,10 @@ static int mISDNlib_debug(const char *file, int line, const char *func, int __at
int main(int argc, char *argv[])
{
int argi, rc;
int misdn_initialized = 0;
int ph_drv_initialized = 0;
int layer3_initialized = 0;
struct ph_socket_driver ph_drv;
g711_init();
@ -318,16 +329,42 @@ int main(int argc, char *argv[])
if (argi <= 0)
return argi;
/* misdn init and debug */
rc = check_mISDN_dsp();
if (rc)
if (!misdn_kernel && !misdn_user) {
fprintf(stderr, "You defined no mISDN port or layer 1 socket. You must define either one of them! Use '-h' for help.\n");
goto error;
}
if (misdn_kernel && misdn_user) {
fprintf(stderr, "You defined mISDN port and layer 1 socket. You must define either one of them!\n");
goto error;
}
/* check for DSP (kernel only) */
if (misdn_kernel) {
rc = check_mISDN_dsp();
if (rc)
goto error;
}
/* init user space mISDN */
if (misdn_user) {
rc = mISDNInit((debug_mISDN) ? 0xffffffff : 0);
if (rc)
goto error;
misdn_initialized = 1;
rc = init_ph_socket_driver(&ph_drv, isdn_ep, portname, 0, ntmode, (debug_mISDN) ? 0xffffffff : 0);
if (rc)
goto error;
ph_drv_initialized = 1;
}
/* mISDNuser init and debug */
mi_fn.prt_debug = mISDNlib_debug;
init_layer3(4, &mi_fn);
init_layer3(4, &mi_fn, (misdn_user) ? 1 : 0);
layer3_initialized = 1;
mISDN_set_debug_level((debug_mISDN) ? 0xfffffeff : 0);
rc = isdn_initialize(isdn_ep, law, portname, ntmode, ptp, layer1hold, layer2hold, channel_out, channel_in, timeouts, tx_delay, tx_gain, rx_gain, pipeline, dtmf, local_tones, serving_location);
/* init instance */
rc = isdn_initialize(isdn_ep, (misdn_user) ? &ph_drv.ph_socket : NULL, law, portname, ntmode, ptp, layer1hold, layer2hold, channel_out, channel_in, timeouts, tx_delay, tx_gain, rx_gain, pipeline, dtmf, local_tones, serving_location);
if (rc) {
PDEBUG(DISDN, DEBUG_ERROR, "mISDN initializing failed!\n");
goto error;
@ -353,10 +390,19 @@ int main(int argc, char *argv[])
process_timer();
isdn_bchannel_work(isdn_ep);
isdn_rtp_work(isdn_ep);
if (misdn_user) {
/* run workers of mISDN stacks in user space */
mISDN_work();
}
do {
w = 0;
w |= osmo_cc_handle();
w |= isdn_dchannel_work(isdn_ep);
if (misdn_user) {
/* run workers of mISDN stacks in user space */
w |= ph_socket_work(&ph_drv.ph_socket);
w |= work_layer3(isdn_ep->ml3);
}
} while (w);
usleep(1000);
}
@ -376,6 +422,12 @@ error:
if (layer3_initialized)
cleanup_layer3();
if (ph_drv_initialized)
exit_ph_socket_driver(&ph_drv);
if (misdn_initialized)
mISDN_cleanup();
options_free();
return 0;

@ -0,0 +1,309 @@
/* ph-socket driver for user space mISDN
*
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include "ph_socket.h"
#include "ph_driver.h"
#define __MISDNL1L2__
#include "../libmisdn/mISDNhw.h"
static inline u_int
get_sapi_tei(u_char *p)
{
u_int sapi, tei;
sapi = *p >> 2;
tei = p[1] >> 1;
return sapi | (tei << 8);
}
/* message from mISDN stack to PH-socket */
static int d_msg_down(struct mISDNchannel *ch, struct sk_buff *skb)
{
struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
struct dchannel *dch = container_of(dev, struct dchannel, dev);
struct ph_socket_driver *drv = dch->hw;
struct mISDNhead *hh = mISDN_HEAD_P(skb);
switch (hh->prim) {
case PH_DATA_REQ:
printk(KERN_DEBUG "PH-DATA-REQ to interface (channel=%d, len=%d)\n", drv->dch->slot, skb->len);
ph_socket_tx_msg(&drv->ph_socket, drv->dch->slot, PH_PRIM_DATA_REQ, skb->data, skb->len);
skb_trim(skb, 0);
printk(KERN_DEBUG "PH-DATA-CNF from interface\n");
queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb);
skb = NULL;
break;
case PH_ACTIVATE_REQ:
printk(KERN_DEBUG "PH-ACTIVATE_REQ to interface\n");
ph_socket_tx_msg(&drv->ph_socket, drv->dch->slot, PH_PRIM_ACT_REQ, NULL, 0);
break;
case PH_DEACTIVATE_REQ:
printk(KERN_DEBUG "PH-DEACTIVATE_REQ to interface\n");
ph_socket_tx_msg(&drv->ph_socket, drv->dch->slot, PH_PRIM_DACT_REQ, NULL, 0);
break;
}
if (skb)
dev_kfree_skb(skb);
return 0;
}
/* open sub function of d_ctrl */
static int open_dchannel(struct ph_socket_driver __attribute__((unused)) *drv, struct dchannel *dch, struct channel_req *rq)
{
if (dch->debug & DEBUG_HW_OPEN)
printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
dch->dev.id, __builtin_return_address(0));
if (rq->protocol == ISDN_P_NONE)
return -EINVAL;
if ((dch->dev.D.protocol != ISDN_P_NONE) &&
(dch->dev.D.protocol != rq->protocol)) {
if (dch->debug & DEBUG_HW_OPEN)
printk(KERN_WARNING "%s: change protocol %x to %x\n",
__func__, dch->dev.D.protocol, rq->protocol);
}
if (dch->dev.D.protocol != rq->protocol)
dch->dev.D.protocol = rq->protocol;
if (test_bit(FLG_ACTIVE, &dch->Flags)) {
_queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY,
0, NULL, GFP_KERNEL);
}
rq->ch = &dch->dev.D;
return 0;
}
/* channel sub function of d_ctrl */
static int channel_dctrl(struct dchannel __attribute__((unused)) *dch, struct mISDN_ctrl_req *cq)
{
int ret = 0;
switch (cq->op) {
default:
printk(KERN_WARNING "%s: unknown Op %x\n",
__func__, cq->op);
ret = -EINVAL;
break;
}
return ret;
}
/* control from mISDN stack to this driver */
static int d_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
{
struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
struct dchannel *dch = container_of(dev, struct dchannel, dev);
struct ph_socket_driver *drv = dch->hw;
struct channel_req *rq;
int err = 0;
if (dch->debug & DEBUG_HW)
printk(KERN_DEBUG "%s: cmd:%x %p\n",
__func__, cmd, arg);
switch (cmd) {
case OPEN_CHANNEL:
rq = arg;
switch (rq->protocol) {
case ISDN_P_TE_S0:
case ISDN_P_NT_S0:
if (drv->pri) {
err = -EINVAL;
break;
}
err = open_dchannel(drv, dch, rq);
break;
case ISDN_P_TE_E1:
case ISDN_P_NT_E1:
if (!drv->pri) {
err = -EINVAL;
break;
}
err = open_dchannel(drv, dch, rq);
break;
default:
;
//err = open_bchannel(hc, dch, rq);
}
break;
case CLOSE_CHANNEL:
if (dch->debug & DEBUG_HW_OPEN)
printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
__func__, dch->dev.id,
__builtin_return_address(0));
break;
case CONTROL_CHANNEL:
err = channel_dctrl(dch, arg);
break;
default:
if (dch->debug & DEBUG_HW)
printk(KERN_DEBUG "%s: unknown command %x\n",
__func__, cmd);
err = -EINVAL;
}
return err;
}
/* init instance of PH-socket driver */
int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *socket_name, int pri, int nt, uint32_t debug)
{
int ret = 0;
struct dchannel *dch;
memset(drv, 0, sizeof(*drv));
drv->priv = priv;
drv->pri = pri;
drv->nt = nt;
/* socket client */
ph_socket_init(&drv->ph_socket, drv, socket_name, 0);
/* allocate dchannel structure */
dch = kzalloc(sizeof(*dch), GFP_KERNEL);
if (!dch) {
ret = -ENOMEM;
goto error;
}
/* populate dchannel structure */
dch->debug = debug;
mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, NULL);
dch->hw = drv;
if (pri) {
if (nt)
dch->dev.Dprotocols = (1 << ISDN_P_NT_E1);
else
dch->dev.Dprotocols = (1 << ISDN_P_TE_E1);
dch->dev.nrbchan = 30;
} else {
if (nt)
dch->dev.Dprotocols = (1 << ISDN_P_NT_S0);
else
dch->dev.Dprotocols = (1 << ISDN_P_TE_S0);
dch->dev.nrbchan = 2;
}
dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
dch->dev.D.send = d_msg_down;
dch->dev.D.ctrl = d_ctrl;
dch->slot = (pri) ? 16 : 3;
dch->dev.nrbchan = 0;
/* register dchannel to mISDN */
ret = mISDN_register_device(&dch->dev, NULL, "ph-socket");
if (ret) {
kfree(dch);
return ret;
}
/* link */
drv->dch = dch;
return 0;
error:
exit_ph_socket_driver(drv);
return ret;
}
/* destroy instance of PH-socket driver */
void exit_ph_socket_driver(struct ph_socket_driver *drv)
{
/* unregister dchannel structure and free */
if (drv->dch) {
mISDN_unregister_device(&drv->dch->dev);
mISDN_freedchannel(drv->dch);
kfree(drv->dch);
drv->dch = NULL;
}
/* close socket */
ph_socket_exit(&drv->ph_socket);
}
/* message from PH-socket to mISDN */
void ph_socket_rx_msg(ph_socket_t *s, int channel, uint8_t prim, uint8_t *data, int length)
{
struct ph_socket_driver *drv = (struct ph_socket_driver *)s->priv;
/* stack not complete */
if (!drv || !drv->dch)
return;
switch (prim) {
case PH_PRIM_DATA_IND:
if (drv->dch->slot == channel) {
printk(KERN_DEBUG "PH-DATA-IND from interface (channel %d, len=%d)\n", channel, length);
if (length < 2) {
printk(KERN_ERR "%s: Message too short!\n", __func__);
break;
}
_queue_data(&drv->dch->dev.D, PH_DATA_IND, get_sapi_tei(data), length, data, GFP_ATOMIC);
break;
}
bchannel_ph_sock_receive(drv->priv, channel, prim, data, length);
break;
case PH_PRIM_ACT_IND:
if (drv->dch->slot == channel) {
printk(KERN_DEBUG "PH-ACTIVATE-IND from interface (dchannel)\n");
drv->activated = 1;
_queue_data(&drv->dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
break;
}
printk(KERN_DEBUG "PH-ACTIVATE-IND from interface (bchannel)\n");
bchannel_ph_sock_receive(drv->priv, channel, prim, data, length);
break;
case PH_PRIM_DACT_IND:
if (drv->dch->slot == channel) {
printk(KERN_DEBUG "PH-DEACTIVATE-IND from interface (dchannel)\n");
drv->activated = 0;
_queue_data(&drv->dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
break;
}
printk(KERN_DEBUG "PH-DEACTIVATE-IND from interface (bchannel)\n");
bchannel_ph_sock_receive(drv->priv, channel, prim, data, length);
break;
case PH_PRIM_CTRL_IND:
if (length >= 1) {
switch (data[0]) {
case PH_CTRL_ENABLE:
printk(KERN_DEBUG "PH-SOCKET Interface available\n");
drv->enabled = 1;
break;
case PH_CTRL_DISABLE:
printk(KERN_DEBUG "PH-SOCKET Interface unavailable\n");
drv->enabled = 0;
if (drv->activated) {
drv->activated = 0;
_queue_data(&drv->dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
}
break;
}
}
break;
default:
printk(KERN_ERR "%s: Rejecting unknown message 0x%02x from PH-socket!\n", __func__, prim);
}
}

@ -0,0 +1,14 @@
struct ph_socket_driver {
void *priv;
int pri, nt;
ph_socket_t ph_socket;
struct dchannel *dch;
int enabled, activated;
};
int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *socket_name, int pri, int nt, uint32_t debug);
void exit_ph_socket_driver(struct ph_socket_driver *drv);
void bchannel_ph_sock_receive(void *priv, int channel, uint8_t prim, uint8_t *data, int length);

@ -0,0 +1 @@
/files/projects/uk0/src/uk0/ph_socket.c

@ -0,0 +1 @@
/files/projects/uk0/src/uk0/ph_socket.h

@ -24,7 +24,10 @@
#include <stdint.h>
#include <errno.h>
#include <math.h>
#include <time.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include "debug.h"
const char *debug_level[] = {
@ -53,6 +56,8 @@ struct debug_cat {
{ "mpt1327", "\033[1;34m" },
{ "jollycom", "\033[1;34m" },
{ "eurosignal", "\033[1;34m" },
{ "pocsag", "\033[1;34m" },
{ "5-ton-folge", "\033[1;34m" },
{ "frame", "\033[0;36m" },
{ "call", "\033[0;37m" },
{ "cc", "\033[1;32m" },
@ -85,10 +90,13 @@ struct debug_cat {
{ "dss1", "\033[1;34m" },
{ "sip", "\033[1;35m" },
{ "telephone", "\033[1;34m" },
{ "UK0", "\033[0;31m" },
{ "ph", "\033[0;33m" },
{ NULL, NULL }
};
int debuglevel = DEBUG_INFO;
int debug_date = 0;
uint64_t debug_mask = ~0;
extern int num_kanal;
@ -97,6 +105,28 @@ void (*print_console_text)(void) = NULL;
int debug_limit_scroll = 0;
static int lock_initialized = 0;
static pthread_mutex_t debug_mutex;
void lock_debug(void)
{
int rc;
if (!lock_initialized) {
rc = pthread_mutex_init(&debug_mutex, NULL);
if (rc == 0)
lock_initialized = 1;
}
if (lock_initialized)
pthread_mutex_lock(&debug_mutex);
}
void unlock_debug(void)
{
if (lock_initialized)
pthread_mutex_unlock(&debug_mutex);
}
void get_win_size(int *w, int *h)
{
struct winsize win;
@ -124,6 +154,11 @@ void _printdebug(const char *file, const char __attribute__((unused)) *function,
if (debuglevel > level)
return;
if (!(debug_mask & ((uint64_t)1 << cat)))
return;
lock_debug();
buffer[sizeof(buffer) - 1] = '\0';
/* if kanal is used, prefix the channel number */
@ -133,9 +168,6 @@ void _printdebug(const char *file, const char __attribute__((unused)) *function,
s -= strlen(buffer);
}
if (!(debug_mask & ((uint64_t)1 << cat)))
return;
va_start(args, fmt);
vsnprintf(b, s, fmt, args);
va_end(args);
@ -148,12 +180,23 @@ void _printdebug(const char *file, const char __attribute__((unused)) *function,
get_win_size(&w, &h);
printf("\0337\033[%d;%dr\0338", debug_limit_scroll + 1, h);
}
if (debug_date) {
struct timeval tv;
struct tm *tm;
gettimeofday(&tv, NULL);
tm = localtime(&tv.tv_sec);
printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 10000.0));
}
printf("%s%s:%4d %s: %s\033[0;39m", debug_cat[cat].color, file, line, debug_level[level], buffer);
if (debug_limit_scroll)
printf("\0337\033[%d;%dr\0338", 1, h);
if (print_console_text)
print_console_text();
fflush(stdout);
unlock_debug();
}
const char *debug_amplitude(double level)
@ -190,6 +233,17 @@ const char *debug_db(double level_db)
return text;
}
void debug_print_help(void)
{
printf(" -v --verbose <level> | <level>,<category>[,<category>[,...]] | list\n");
printf(" Use 'list' to get a list of all levels and categories\n");
printf(" Verbose level: digit of debug level (default = '%d')\n", debuglevel);
printf(" Verbose level+category: level digit followed by one or more categories\n");
printf(" -> If no category is specified, all categories are selected\n");
printf(" -v --verbose date\n");
printf(" Show date with debug output\n");
}
void debug_list_cat(void)
{
int i;
@ -210,6 +264,11 @@ int parse_debug_opt(const char *optarg)
int i, max_level = 0;
char *dup, *dstring, *p;
if (!strcasecmp(optarg, "date")) {
debug_date = 1;
return 0;
}
for (i = 0; debug_level[i]; i++)
max_level = i;

@ -18,38 +18,45 @@
#define DMPT1327 11
#define DJOLLY 12
#define DEURO 13
#define DFRAME 14
#define DCALL 15
#define DCC 16
#define DDB 17
#define DTRANS 18
#define DDMS 19
#define DSMS 20
#define DSDR 21
#define DUHD 22
#define DSOAPY 23
#define DWAVE 24