blob: bb940fee23d72c1b94f36dfcafc470aa3e5dc037 [file] [log] [blame]
Harald Weltec12d52b2009-02-01 21:39:06 +00001/* OpenBSC BS-11 T-Link interface using POSIX serial port */
2
3/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01008 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
Harald Weltec12d52b2009-02-01 21:39:06 +000010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * GNU Affero General Public License for more details.
Harald Weltec12d52b2009-02-01 21:39:06 +000016 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Weltec12d52b2009-02-01 21:39:06 +000019 *
20 */
21
22#include <unistd.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <errno.h>
26#include <string.h>
27#include <termios.h>
28#include <fcntl.h>
29
Harald Weltedfe6c7d2010-02-20 16:24:02 +010030#include <osmocore/select.h>
31#include <osmocore/msgb.h>
Harald Weltec12d52b2009-02-01 21:39:06 +000032#include <openbsc/debug.h>
33#include <openbsc/gsm_data.h>
Harald Welte099d6102009-02-21 12:59:58 +000034#include <openbsc/rs232.h>
Harald Weltec12d52b2009-02-01 21:39:06 +000035
36/* adaption layer from GSM 08.59 + 12.21 to RS232 */
37
38struct serial_handle {
39 struct bsc_fd fd;
40 struct llist_head tx_queue;
41
42 struct msgb *rx_msg;
43 unsigned int rxmsg_bytes_missing;
44
45 unsigned int delay_ms;
Harald Welte273feca2009-03-28 16:53:25 +000046 struct gsm_bts *bts;
Harald Weltec12d52b2009-02-01 21:39:06 +000047};
48
49/* FIXME: this needs to go */
50static struct serial_handle _ser_handle, *ser_handle = &_ser_handle;
51
52#define LAPD_HDR_LEN 10
53
Harald Weltef80b7d32009-02-19 03:11:13 +000054static int handle_ser_write(struct bsc_fd *bfd);
55
Harald Weltec12d52b2009-02-01 21:39:06 +000056/* callback from abis_nm */
57int _abis_nm_sendmsg(struct msgb *msg)
58{
59 struct serial_handle *sh = ser_handle;
60 u_int8_t *lapd;
61 unsigned int len;
62
63 msg->l2h = msg->data;
64
65 /* prepend LAPD header */
66 lapd = msgb_push(msg, LAPD_HDR_LEN);
67
68 len = msg->len - 2;
69
70 lapd[0] = (len >> 8) & 0xff;
71 lapd[1] = len & 0xff; /* length of bytes startign at lapd[2] */
72 lapd[2] = 0x00;
73 lapd[3] = 0x07;
74 lapd[4] = 0x01;
75 lapd[5] = 0x3e;
76 lapd[6] = 0x00;
77 lapd[7] = 0x00;
78 lapd[8] = msg->len - 10; /* length of bytes starting at lapd[10] */
79 lapd[9] = lapd[8] ^ 0x38;
80
81 msgb_enqueue(&sh->tx_queue, msg);
82 sh->fd.when |= BSC_FD_WRITE;
83
Harald Weltef80b7d32009-02-19 03:11:13 +000084 /* we try to immediately send */
85 handle_ser_write(&sh->fd);
86
Harald Weltec12d52b2009-02-01 21:39:06 +000087 return 0;
88}
89
90/* select.c callback in case we can write to the RS232 */
91static int handle_ser_write(struct bsc_fd *bfd)
92{
93 struct serial_handle *sh = bfd->data;
94 struct msgb *msg;
95 int written;
96
97 msg = msgb_dequeue(&sh->tx_queue);
98 if (!msg) {
99 bfd->when &= ~BSC_FD_WRITE;
100 return 0;
101 }
102
Harald Weltec50ea842009-04-29 22:32:10 +0000103 DEBUGP(DMI, "RS232 TX: %s\n", hexdump(msg->data, msg->len));
Harald Weltec12d52b2009-02-01 21:39:06 +0000104
105 /* send over serial line */
106 written = write(bfd->fd, msg->data, msg->len);
107 if (written < msg->len) {
108 perror("short write:");
109 msgb_free(msg);
110 return -1;
111 }
112
113 msgb_free(msg);
114 usleep(sh->delay_ms*1000);
115
116 return 0;
117}
118
119#define SERIAL_ALLOC_SIZE 300
120
121/* select.c callback in case we can read from the RS232 */
122static int handle_ser_read(struct bsc_fd *bfd)
123{
124 struct serial_handle *sh = bfd->data;
125 struct msgb *msg;
126 int rc = 0;
127
128 if (!sh->rx_msg) {
Harald Welte966636f2009-06-26 19:39:35 +0200129 sh->rx_msg = msgb_alloc(SERIAL_ALLOC_SIZE, "RS232 Rx");
Harald Weltec12d52b2009-02-01 21:39:06 +0000130 sh->rx_msg->l2h = NULL;
Harald Welte273feca2009-03-28 16:53:25 +0000131 sh->rx_msg->trx = sh->bts->c0;
Harald Weltec12d52b2009-02-01 21:39:06 +0000132 }
133 msg = sh->rx_msg;
134
135 /* first read two byes to obtain length */
136 if (msg->len < 2) {
137 rc = read(sh->fd.fd, msg->tail, 2 - msg->len);
138 if (rc < 0) {
139 perror("ERROR reading from serial port");
140 msgb_free(msg);
141 return rc;
142 }
143 msgb_put(msg, rc);
144
145 if (msg->len >= 2) {
146 /* parse LAPD payload length */
147 if (msg->data[0] != 0)
148 fprintf(stderr, "Suspicious header byte 0: 0x%02x\n",
149 msg->data[0]);
150
151 sh->rxmsg_bytes_missing = msg->data[0] << 8;
152 sh->rxmsg_bytes_missing += msg->data[1];
153
154 if (sh->rxmsg_bytes_missing < LAPD_HDR_LEN -2)
155 fprintf(stderr, "Invalid length in hdr: %u\n",
156 sh->rxmsg_bytes_missing);
157 }
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200158 } else {
Harald Weltec12d52b2009-02-01 21:39:06 +0000159 /* try to read as many of the missing bytes as are available */
160 rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing);
161 if (rc < 0) {
162 perror("ERROR reading from serial port");
163 msgb_free(msg);
164 return rc;
165 }
166 msgb_put(msg, rc);
167 sh->rxmsg_bytes_missing -= rc;
168
169 if (sh->rxmsg_bytes_missing == 0) {
170 /* we have one complete message now */
171 sh->rx_msg = NULL;
172
173 if (msg->len > LAPD_HDR_LEN)
174 msg->l2h = msg->data + LAPD_HDR_LEN;
175
Harald Welte3cc4bf52009-02-28 13:08:01 +0000176 DEBUGP(DMI, "RS232 RX: %s\n", hexdump(msg->data, msg->len));
Harald Weltec12d52b2009-02-01 21:39:06 +0000177 rc = handle_serial_msg(msg);
178 }
179 }
180
181 return rc;
182}
183
184/* select.c callback */
185static int serial_fd_cb(struct bsc_fd *bfd, unsigned int what)
186{
187 int rc = 0;
188
189 if (what & BSC_FD_READ)
190 rc = handle_ser_read(bfd);
191
192 if (rc < 0)
193 return rc;
194
195 if (what & BSC_FD_WRITE)
196 rc = handle_ser_write(bfd);
197
198 return rc;
199}
200
Harald Welte273feca2009-03-28 16:53:25 +0000201int rs232_setup(const char *serial_port, unsigned int delay_ms,
202 struct gsm_bts *bts)
Harald Weltec12d52b2009-02-01 21:39:06 +0000203{
204 int rc, serial_fd;
205 struct termios tio;
206
207 serial_fd = open(serial_port, O_RDWR);
208 if (serial_fd < 0) {
209 perror("cannot open serial port:");
210 return serial_fd;
211 }
212
213 /* set baudrate */
214 rc = tcgetattr(serial_fd, &tio);
215 if (rc < 0) {
216 perror("tcgetattr()");
217 return rc;
218 }
219 cfsetispeed(&tio, B19200);
220 cfsetospeed(&tio, B19200);
221 tio.c_cflag |= (CREAD | CLOCAL | CS8);
222 tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
223 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
224 tio.c_iflag |= (INPCK | ISTRIP);
225 tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR);
226 tio.c_oflag &= ~(OPOST);
227 rc = tcsetattr(serial_fd, TCSADRAIN, &tio);
228 if (rc < 0) {
229 perror("tcsetattr()");
230 return rc;
231 }
232
233 INIT_LLIST_HEAD(&ser_handle->tx_queue);
234 ser_handle->fd.fd = serial_fd;
235 ser_handle->fd.when = BSC_FD_READ;
236 ser_handle->fd.cb = serial_fd_cb;
237 ser_handle->fd.data = ser_handle;
238 ser_handle->delay_ms = delay_ms;
Harald Welte273feca2009-03-28 16:53:25 +0000239 ser_handle->bts = bts;
Harald Weltec12d52b2009-02-01 21:39:06 +0000240 rc = bsc_register_fd(&ser_handle->fd);
241 if (rc < 0) {
242 fprintf(stderr, "could not register FD: %s\n",
243 strerror(rc));
244 return rc;
245 }
246
247 return 0;
248}