diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1669fca --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.o +.idea +pjsip.install +slmodemd/.build_profile +d-modem +slmodemd +modem_test \ No newline at end of file diff --git a/README.md b/README.md index efecfe9..e6b7448 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ The repository contains two applications: slmodemd – A stripped down and patched version of Debian’s sl-modem-daemon package. All kernel driver code has been replaced with socket-based communication, allowing external applications to manage audio streams. -d-modem – External application that interfaces with slmodemd to manage SIP calls and their associated audio streams. +d-modem – External application that interfaces with slmodemd to manage SIP calls and their associated audio streams. + +socat.sh - Script that invokes Socat, connecting 2 modems together and transferring data between them via TCP relay (see [Testing](#testing)). After they have been built, you will need to configure SIP account information in the SIP_LOGIN environment variable: @@ -40,7 +42,7 @@ Because there isn’t any dial tone on our SIP connection, you’ll need to disa atx3 OK -To successfully connect, you will likely need to manually select a modulation and data rate. In our testing, V.32bis (14.4kbps) and below appears to be the most reliable, though V.34 (33.6kbps) connections are sometimes successful. For example, the following command selects V.32bis with a data rate of 4800 – 9600 bps. Refer to the manual for further details. +To successfully connect, you will likely need to manually select a modulation and data rate. In our testing, V.32bis (14.4kbps) and below appears to be the most reliable, though V.34 (33.6kbps) connections are sometimes successful. For example, the following command selects V.32bis with a data rate of 4800 – 9600 bps. Refer to [the manual](./doc/ST56ATCommands.pdf) for further details. at+ms=132,0,4800,9600 OK @@ -60,12 +62,54 @@ Finally, dial the number of the target system. Below shows a connection to the 59515 21-10-28 21:40:21 11 0 -.1 045.0 UTC(NIST) * 59515 21-10-28 21:40:22 11 0 -.1 045.0 UTC(NIST) * 59515 21-10-28 21:40:23 11 0 -.1 045.0 UTC(NIST) * - + +## Testing +Install multipurpose relay Socat and Minicom. + +Run slmodemd from 2 terminals, passing the path to socat.sh in the -e option and specifying different modem devices. + + # ./slmodemd/slmodemd -d2 -e ./socat.sh /dev/slamr0 + + # ./slmodemd/slmodemd -d2 -e ./socat.sh /dev/slamr1 + +In 2 other terminals, connect to the newly created serial devices: + + # minicom -D /dev/ttySL0 + + # minicom -D /dev/ttySL1 + +Because there isn’t any dial tone on our network connection, disable dial tone detection: + + atx3 + OK + +To successfully connect, you will likely need to manually select a modulation and data rate: + + at+ms=132,1,,14400 + OK + +Put one modem in answering mode: + + ata + +Finally, dial the number of the second system. 2130706433 is a decimal number of localhost IP address 127.0.0.1. If you run second modem on another machine, convert its IP address to a decimal number and dial. + + atd2130706433 + +Now modems are connected and can interact with each other: + + CONNECT 9600 + +To stop data transmission, first escape from on-line mode (+++), then hang up: + + +++ + ath + ## Known Issues / Future Work - Connections are unreliable, and it is currently difficult to connect at speeds higher than 14.4kbps or so. It might be possible to improve this by disabling/reconfiguring PJSIP’s jitter buffer. - Additional logging/error handling is needed - The serial interface could be replaced with stdio or a socket, and common AT configuration options could be exposed as command line options -- There is currently no support for receiving calls +- There is currently no support for receiving calls in d-modem. Copyright 2021 Aon plc diff --git a/doc/ST56ATCommands.pdf b/doc/ST56ATCommands.pdf new file mode 100644 index 0000000..225864b Binary files /dev/null and b/doc/ST56ATCommands.pdf differ diff --git a/slmodemd/modem_at.c b/slmodemd/modem_at.c index a573bfc..73b727a 100644 --- a/slmodemd/modem_at.c +++ b/slmodemd/modem_at.c @@ -136,6 +136,7 @@ static int process_A(struct modem *m, char *p, int *len) { int ret; AT_DBG("AT A command...\n"); + memset(m->dial_string, 0, strlen(m->dial_string)); ret = modem_answer(m); if (ret) return -1; diff --git a/slmodemd/modem_cmdline.c b/slmodemd/modem_cmdline.c index 9f80619..ec20a91 100644 --- a/slmodemd/modem_cmdline.c +++ b/slmodemd/modem_cmdline.c @@ -125,7 +125,7 @@ static struct opt { {'s',"shortbuffer","use short buffer (4 periods length)"}, {'d',"debug","debug level (developers only, for ./sl...)",OPTIONAL,INTEGER,"0"}, {'l',"log","logging mode",OPTIONAL,INTEGER,"5"}, - {'e',"exec","path to external application that transmits audio over the socket (required)"}, + {'e',"exec","path to external application that transmits audio over the socket (required)",MANDATORY,STRING,""}, {} }; diff --git a/slmodemd/modem_main.c b/slmodemd/modem_main.c index 998090a..982f04b 100644 --- a/slmodemd/modem_main.c +++ b/slmodemd/modem_main.c @@ -136,6 +136,7 @@ struct device_struct { static char inbuf[4096]; static char outbuf[4096]; +static pid_t pid; /* * ALSA 'driver' @@ -626,7 +627,7 @@ static int socket_start (struct modem *m) exit(-1); } - pid_t pid = fork(); + pid = fork(); if (pid == -1) { perror("fork"); exit(-1); @@ -635,7 +636,13 @@ static int socket_start (struct modem *m) char str[16]; snprintf(str,sizeof(str),"%d",sockets[0]); close(sockets[1]); - execl(modem_exec,modem_exec,m->dial_string,str,NULL); + + ret = execl(modem_exec,modem_exec,m->dial_string,str,NULL); + if (ret == -1) { + ERR("prog: %s\n", modem_exec); + perror("execl"); + exit(-1); + } } else { close(sockets[0]); dev->fd = sockets[1]; @@ -645,8 +652,6 @@ static int socket_start (struct modem *m) ret = write(dev->fd, outbuf, ret); DBG("done delay thing\n"); if (ret < 0) { - close(dev->fd); - dev->fd = -1; return ret; } dev->delay = ret/2; @@ -658,9 +663,8 @@ static int socket_stop (struct modem *m) { struct device_struct *dev = m->dev_data; DBG("socket_stop...\n"); - close(dev->fd); - dev->fd = -1; - wait(NULL); // for exec'ed child + DBG("kill -%d %d\n", SIGTERM, pid); + kill(pid, SIGTERM); // terminate exec'ed child return 0; } @@ -758,6 +762,8 @@ static int mdm_device_release(struct device_struct *dev) static int socket_device_setup(struct device_struct *dev, const char *dev_name) { memset(dev,0,sizeof(*dev)); + unsigned int pos = strlen(dev_name)-1; + dev->num = atoi(&dev_name[pos]); return 0; } @@ -969,10 +975,6 @@ static int modem_run(struct modem *m, struct device_struct *dev) } modem_process(m,inbuf,outbuf,count); - if (dev->fd == -1) { - DBG("closed connection to child socket process\n"); - continue; - } count = device_write(dev,outbuf,count); if(count < 0) { ERR("dev write: %s\n",strerror(errno)); @@ -1112,6 +1114,7 @@ int modem_main(const char *dev_name) signal(SIGINT, mark_termination); signal(SIGTERM, mark_termination); + signal(SIGCHLD, SIG_IGN); #ifdef SLMODEMD_USER if (need_realtime) { diff --git a/socat.sh b/socat.sh new file mode 100755 index 0000000..839e88a --- /dev/null +++ b/socat.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +PORT=1234 + +if [ -z $1 ]; +then + exec socat tcp-listen:$PORT fd:$2 +else + exec socat tcp-connect:$1:$PORT fd:$2 +fi \ No newline at end of file