요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
==============================
GSM 0710 tty multiplexor HOWTO
==============================
.. contents:: :local:
This line discipline implements the GSM 07.10 multiplexing protocol
detailed in the following 3GPP document:
https://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip
This document give some hints on how to use this driver with GPRS and 3G
modems connected to a physical serial port.
How to use it
=============
Config Initiator
----------------
#. Initialize the modem in 0710 mux mode (usually ``AT+CMUX=`` command) through
its serial port. Depending on the modem used, you can pass more or less
parameters to this command.
#. Switch the serial line to using the n_gsm line discipline by using
``TIOCSETD`` ioctl.
#. Configure the mux using ``GSMIOC_GETCONF_EXT``/``GSMIOC_SETCONF_EXT`` ioctl if needed.
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
#. Configure DLCs using ``GSMIOC_GETCONF_DLCI``/``GSMIOC_SETCONF_DLCI`` ioctl for non-defaults.
#. Obtain base gsmtty number for the used serial port.
Major parts of the initialization program
(a good starting point is util-linux-ng/sys-utils/ldattach.c)::
#include <stdio.h>
#include <stdint.h>
#include <linux/gsmmux.h>
#include <linux/tty.h>
#define DEFAULT_SPEED B115200
#define SERIAL_PORT /dev/ttyS0
int ldisc = N_GSM0710;
struct gsm_config c;
struct gsm_config_ext ce;
struct gsm_dlci_config dc;
struct termios configuration;
uint32_t first;
/* open the serial port connected to the modem */
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
/* configure the serial port : speed, flow control ... */
/* send the AT commands to switch the modem to CMUX mode
and check that it's successful (should return OK) */
write(fd, "AT+CMUX=0\r", 10);
/* experience showed that some modems need some time before
being able to answer to the first MUX packet so a delay
may be needed here in some case */
sleep(3);
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm extended configuration */
ioctl(fd, GSMIOC_GETCONF_EXT, &ce);
/* use keep-alive once every 5s for modem connection supervision */
ce.keep_alive = 500;
/* set the new extended configuration */
ioctl(fd, GSMIOC_SETCONF_EXT, &ce);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are initiator and need encoding 0 (basic) */
c.initiator = 1;
c.encapsulation = 0;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(fd, GSMIOC_SETCONF, &c);
/* get DLC 1 configuration */
dc.channel = 1;
ioctl(fd, GSMIOC_GETCONF_DLCI, &dc);
/* the first user channel gets a higher priority */
dc.priority = 1;
/* set the new DLC 1 specific configuration */
ioctl(fd, GSMIOC_SETCONF_DLCI, &dc);
/* get first gsmtty device node */
ioctl(fd, GSMIOC_GETFIRST, &first);
printf("first muxed line: /dev/gsmtty%i\n", first);
/* and wait for ever to keep the line discipline enabled */
daemon(0,0);
pause();
#. Use these devices as plain serial ports.
For example, it's possible:
- to use *gnokii* to send / receive SMS on ``ttygsm1``
- to use *ppp* to establish a datalink on ``ttygsm2``
#. First close all virtual ports before closing the physical port.
Note that after closing the physical port the modem is still in multiplexing
mode. This may prevent a successful re-opening of the port later. To avoid
this situation either reset the modem if your hardware allows that or send
a disconnect command frame manually before initializing the multiplexing mode
for the second time. The byte sequence for the disconnect command frame is::
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9
Config Requester
----------------
#. Receive ``AT+CMUX=`` command through its serial port, initialize mux mode
config.
#. Switch the serial line to using the *n_gsm* line discipline by using
``TIOCSETD`` ioctl.
#. Configure the mux using ``GSMIOC_GETCONF_EXT``/``GSMIOC_SETCONF_EXT``
ioctl if needed.
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
#. Configure DLCs using ``GSMIOC_GETCONF_DLCI``/``GSMIOC_SETCONF_DLCI`` ioctl for non-defaults.
#. Obtain base gsmtty number for the used serial port::
#include <stdio.h>
#include <stdint.h>
#include <linux/gsmmux.h>
#include <linux/tty.h>
#define DEFAULT_SPEED B115200
#define SERIAL_PORT /dev/ttyS0
int ldisc = N_GSM0710;
struct gsm_config c;
struct gsm_config_ext ce;
struct gsm_dlci_config dc;
struct termios configuration;
uint32_t first;
/* open the serial port */
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
/* configure the serial port : speed, flow control ... */
/* get serial data and check "AT+CMUX=command" parameter ... */
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm extended configuration */
ioctl(fd, GSMIOC_GETCONF_EXT, &ce);
/* use keep-alive once every 5s for peer connection supervision */
ce.keep_alive = 500;
/* set the new extended configuration */
ioctl(fd, GSMIOC_SETCONF_EXT, &ce);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are requester and need encoding 0 (basic) */
c.initiator = 0;
c.encapsulation = 0;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(fd, GSMIOC_SETCONF, &c);
/* get DLC 1 configuration */
dc.channel = 1;
ioctl(fd, GSMIOC_GETCONF_DLCI, &dc);
/* the first user channel gets a higher priority */
dc.priority = 1;
/* set the new DLC 1 specific configuration */
ioctl(fd, GSMIOC_SETCONF_DLCI, &dc);
/* get first gsmtty device node */
ioctl(fd, GSMIOC_GETFIRST, &first);
printf("first muxed line: /dev/gsmtty%i\n", first);
/* and wait for ever to keep the line discipline enabled */
daemon(0,0);
pause();
11-03-08 - Eric Bénard - <[email protected]>
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
GSM 07.10 TTY multiplexor 개요
1-17이 line discipline은 아래 3GPP 문서에 정의된 GSM 07.10 multiplexing protocol을 구현합니다.
프로토콜 규격은 `https://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip`에서 확인할 수 있습니다. 이 문서는 물리 serial port에 연결한 GPRS 및 3G modem에서 이 드라이버를 사용하는 방법을 안내합니다.
==============================
GSM 0710 tty multiplexor HOWTO
==============================
.. contents:: :local:
This line discipline implements the GSM 07.10 multiplexing protocol
detailed in the following 3GPP document:
https://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip
This document give some hints on how to use this driver with GPRS and 3G
modems connected to a physical serial port.
How to use it
=============
Config Initiator 초기화 절차
18-37Initiator는 먼저 modem의 serial port를 통해 보통 `AT+CMUX=` command를 보내 0710 mux mode를 초기화합니다. 전달할 수 있는 매개변수의 수와 종류는 modem에 따라 다릅니다.
그 다음 `TIOCSETD` ioctl로 serial line을 `n_gsm` line discipline으로 전환합니다. 필요한 경우 `GSMIOC_GETCONF_EXT`와 `GSMIOC_SETCONF_EXT`로 확장 설정을 조정하고, `GSMIOC_GETCONF`와 `GSMIOC_SETCONF`로 기본 mux 설정을 구성합니다.
기본값과 다른 Data Link Connection Identifier(DLCI)는 `GSMIOC_GETCONF_DLCI`와 `GSMIOC_SETCONF_DLCI`로 설정합니다. 마지막으로 사용 중인 serial port에 할당된 첫 `gsmtty` 번호를 얻습니다. 초기화 프로그램은 `util-linux-ng/sys-utils/ldattach.c`를 좋은 출발점으로 삼을 수 있습니다.
CMUX 진입부터 첫 gsmtty 번호 획득까지의 ioctl 흐름입니다.
Config Initiator
----------------
#. Initialize the modem in 0710 mux mode (usually ``AT+CMUX=`` command) through
its serial port. Depending on the modem used, you can pass more or less
parameters to this command.
#. Switch the serial line to using the n_gsm line discipline by using
``TIOCSETD`` ioctl.
#. Configure the mux using ``GSMIOC_GETCONF_EXT``/``GSMIOC_SETCONF_EXT`` ioctl if needed.
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
#. Configure DLCs using ``GSMIOC_GETCONF_DLCI``/``GSMIOC_SETCONF_DLCI`` ioctl for non-defaults.
#. Obtain base gsmtty number for the used serial port.
Major parts of the initialization program
(a good starting point is util-linux-ng/sys-utils/ldattach.c)::
Initiator 초기화 코드
38-100예제는 `stdio.h`, `stdint.h`, `linux/gsmmux.h`, `linux/tty.h`를 포함하고 기본 속도를 `B115200`, serial port를 `/dev/ttyS0`로 정의합니다. `N_GSM0710`, `gsm_config`, `gsm_config_ext`, `gsm_dlci_config`, `termios`, 첫 장치 번호를 담을 `uint32_t` 변수를 준비합니다.
modem에 연결된 serial port를 `O_RDWR | O_NOCTTY | O_NDELAY`로 연 뒤 속도와 flow control을 설정합니다. `AT+CMUX=0 `을 보내고 성공 응답 `OK`를 확인해야 합니다. 일부 modem은 첫 MUX packet에 응답할 준비 시간이 필요하므로 예제는 `sleep(3)` 지연을 둡니다.
`TIOCSETD`로 `n_gsm`을 활성화한 후 확장 설정을 읽어 `ce.keep_alive = 500`으로 지정합니다. 이 값은 modem connection supervision을 위해 5초마다 keep-alive를 사용한다는 뜻이며, 변경한 설정을 `GSMIOC_SETCONF_EXT`로 기록합니다.
기본 설정에서는 이 쪽이 initiator이므로 `c.initiator = 1`, basic encoding을 위해 `c.encapsulation = 0`을 사용합니다. modem의 기본 최대 frame size에 맞춰 `c.mru = 127`, `c.mtu = 127`로 설정하고 `GSMIOC_SETCONF`로 적용합니다.
DLC 1을 읽어 첫 user channel의 우선순위를 높이기 위해 `dc.channel = 1`, `dc.priority = 1`로 설정한 뒤 `GSMIOC_SETCONF_DLCI`로 기록합니다. `GSMIOC_GETFIRST`로 첫 device node 번호를 받아 `/dev/gsmtty%i` 형식으로 출력합니다.
마지막의 `daemon(0,0)`과 `pause()`는 line discipline이 계속 활성화되도록 프로세스를 daemon으로 전환하고 무기한 대기시킵니다.
#include <stdio.h>
#include <stdint.h>
#include <linux/gsmmux.h>
#include <linux/tty.h>
#define DEFAULT_SPEED B115200
#define SERIAL_PORT /dev/ttyS0
int ldisc = N_GSM0710;
struct gsm_config c;
struct gsm_config_ext ce;
struct gsm_dlci_config dc;
struct termios configuration;
uint32_t first;
/* open the serial port connected to the modem */
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
/* configure the serial port : speed, flow control ... */
/* send the AT commands to switch the modem to CMUX mode
and check that it's successful (should return OK) */
write(fd, "AT+CMUX=0\r", 10);
/* experience showed that some modems need some time before
being able to answer to the first MUX packet so a delay
may be needed here in some case */
sleep(3);
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm extended configuration */
ioctl(fd, GSMIOC_GETCONF_EXT, &ce);
/* use keep-alive once every 5s for modem connection supervision */
ce.keep_alive = 500;
/* set the new extended configuration */
ioctl(fd, GSMIOC_SETCONF_EXT, &ce);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are initiator and need encoding 0 (basic) */
c.initiator = 1;
c.encapsulation = 0;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(fd, GSMIOC_SETCONF, &c);
/* get DLC 1 configuration */
dc.channel = 1;
ioctl(fd, GSMIOC_GETCONF_DLCI, &dc);
/* the first user channel gets a higher priority */
dc.priority = 1;
/* set the new DLC 1 specific configuration */
ioctl(fd, GSMIOC_SETCONF_DLCI, &dc);
/* get first gsmtty device node */
ioctl(fd, GSMIOC_GETFIRST, &first);
printf("first muxed line: /dev/gsmtty%i\n", first);
/* and wait for ever to keep the line discipline enabled */
daemon(0,0);
pause();
가상 포트 사용과 종료
101-118생성된 device는 일반 serial port처럼 사용할 수 있습니다. 예를 들어 `gnokii`로 `ttygsm1`에서 SMS를 송수신하거나, `ppp`로 `ttygsm2`에 datalink를 만들 수 있습니다.
물리 port를 닫기 전에 모든 virtual port를 먼저 닫아야 합니다. 물리 port를 닫아도 modem은 multiplexing mode에 남으므로, 나중에 port를 다시 열지 못할 수 있습니다.
재초기화 문제를 피하려면 하드웨어가 허용할 경우 modem을 reset하거나, 두 번째 multiplexing mode 초기화 전에 disconnect command frame을 수동 전송합니다. frame byte sequence는 `0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9`입니다.
가상 포트부터 닫고 modem의 mux 상태를 명시적으로 정리합니다.
#. Use these devices as plain serial ports.
For example, it's possible:
- to use *gnokii* to send / receive SMS on ``ttygsm1``
- to use *ppp* to establish a datalink on ``ttygsm2``
#. First close all virtual ports before closing the physical port.
Note that after closing the physical port the modem is still in multiplexing
mode. This may prevent a successful re-opening of the port later. To avoid
this situation either reset the modem if your hardware allows that or send
a disconnect command frame manually before initializing the multiplexing mode
for the second time. The byte sequence for the disconnect command frame is::
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9
Config Requester 초기화 절차
119-135Requester는 serial port로 `AT+CMUX=` command를 수신하고 그 매개변수에 따라 mux mode 설정을 초기화합니다. 직접 command를 보내는 initiator와 시작 방향이 반대입니다.
그 이후에는 `TIOCSETD`로 `n_gsm` line discipline을 선택하고, 필요할 때 `GSMIOC_GETCONF_EXT`·`GSMIOC_SETCONF_EXT`로 확장 설정을 구성합니다. `GSMIOC_GETCONF`·`GSMIOC_SETCONF`로 기본 mux 설정을, `GSMIOC_GETCONF_DLCI`·`GSMIOC_SETCONF_DLCI`로 비기본 DLC를 설정한 뒤 base gsmtty 번호를 얻습니다.
peer가 보낸 CMUX 요청을 받은 뒤 initiator와 같은 설정 계층을 적용합니다.
Config Requester
----------------
#. Receive ``AT+CMUX=`` command through its serial port, initialize mux mode
config.
#. Switch the serial line to using the *n_gsm* line discipline by using
``TIOCSETD`` ioctl.
#. Configure the mux using ``GSMIOC_GETCONF_EXT``/``GSMIOC_SETCONF_EXT``
ioctl if needed.
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
#. Configure DLCs using ``GSMIOC_GETCONF_DLCI``/``GSMIOC_SETCONF_DLCI`` ioctl for non-defaults.
#. Obtain base gsmtty number for the used serial port::
Requester 초기화 코드
136-190Requester 예제도 같은 헤더, `B115200`, `/dev/ttyS0`, `N_GSM0710` 및 설정 구조체를 사용합니다. serial port를 연 뒤 속도와 flow control을 설정하고, 수신한 serial data에서 `AT+CMUX=command` 매개변수를 확인합니다.
`TIOCSETD`로 line discipline을 설정한 뒤 `ce.keep_alive = 500`으로 peer connection supervision용 5초 keep-alive를 적용합니다. 기본 encoding과 frame size도 `c.encapsulation = 0`, `c.mru = 127`, `c.mtu = 127`로 initiator 예제와 같습니다.
역할을 구분하는 핵심은 requester가 `c.initiator = 0`을 설정한다는 점입니다. DLC 1의 우선순위는 동일하게 1로 높이고, `GSMIOC_GETFIRST`로 첫 gsmtty 번호를 출력한 뒤 `daemon(0,0)`과 `pause()`로 line discipline을 유지합니다.
#include <stdio.h>
#include <stdint.h>
#include <linux/gsmmux.h>
#include <linux/tty.h>
#define DEFAULT_SPEED B115200
#define SERIAL_PORT /dev/ttyS0
int ldisc = N_GSM0710;
struct gsm_config c;
struct gsm_config_ext ce;
struct gsm_dlci_config dc;
struct termios configuration;
uint32_t first;
/* open the serial port */
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
/* configure the serial port : speed, flow control ... */
/* get serial data and check "AT+CMUX=command" parameter ... */
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm extended configuration */
ioctl(fd, GSMIOC_GETCONF_EXT, &ce);
/* use keep-alive once every 5s for peer connection supervision */
ce.keep_alive = 500;
/* set the new extended configuration */
ioctl(fd, GSMIOC_SETCONF_EXT, &ce);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are requester and need encoding 0 (basic) */
c.initiator = 0;
c.encapsulation = 0;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(fd, GSMIOC_SETCONF, &c);
/* get DLC 1 configuration */
dc.channel = 1;
ioctl(fd, GSMIOC_GETCONF_DLCI, &dc);
/* the first user channel gets a higher priority */
dc.priority = 1;
/* set the new DLC 1 specific configuration */
ioctl(fd, GSMIOC_SETCONF_DLCI, &dc);
/* get first gsmtty device node */
ioctl(fd, GSMIOC_GETFIRST, &first);
printf("first muxed line: /dev/gsmtty%i\n", first);
/* and wait for ever to keep the line discipline enabled */
daemon(0,0);
pause();
문서 기여 정보
191-192문서 끝에는 `11-03-08 - Eric Bénard - <[email protected]>` 기여 정보가 기록되어 있습니다.
11-03-08 - Eric Bénard - <[email protected]>
요약·해설
n_gsm.rst:1-192`n_gsm`은 한 물리 serial port 위에 여러 GSM 07.10 channel을 구성합니다. initiator는 `AT+CMUX=`를 보내고 `c.initiator = 1`을, requester는 command를 받고 `c.initiator = 0`을 사용합니다. 두 역할 모두 확장·기본·DLCI 설정과 첫 gsmtty 조회를 수행하며, 종료할 때는 가상 포트를 먼저 닫고 modem의 mux 상태를 정리해야 합니다.