blob: a584723641fb8627a902190045a6df9a8f307ae0 [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
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <unistd.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <errno.h>
27#include <string.h>
28#include <termios.h>
29#include <fcntl.h>
30
31#include <openbsc/select.h>
32#include <openbsc/msgb.h>
33#include <openbsc/debug.h>
34#include <openbsc/gsm_data.h>
Harald Welte099d6102009-02-21 12:59:58 +000035#include <openbsc/rs232.h>
Harald Weltec12d52b2009-02-01 21:39:06 +000036
37/* adaption layer from GSM 08.59 + 12.21 to RS232 */
38
39struct serial_handle {
40 struct bsc_fd fd;
41 struct llist_head tx_queue;
42
43 struct msgb *rx_msg;
44 unsigned int rxmsg_bytes_missing;
45
46 unsigned int delay_ms;
Harald Welte273feca2009-03-28 16:53:25 +000047 struct gsm_bts *bts;
Harald Weltec12d52b2009-02-01 21:39:06 +000048};
49
50/* FIXME: this needs to go */
51static struct serial_handle _ser_handle, *ser_handle = &_ser_handle;
52
53#define LAPD_HDR_LEN 10
54
Harald Weltef80b7d32009-02-19 03:11:13 +000055static int handle_ser_write(struct bsc_fd *bfd);
56
Harald Weltec12d52b2009-02-01 21:39:06 +000057/* callback from abis_nm */
58int _abis_nm_sendmsg(struct msgb *msg)
59{
60 struct serial_handle *sh = ser_handle;
61 u_int8_t *lapd;
62 unsigned int len;
63
64 msg->l2h = msg->data;
65
66 /* prepend LAPD header */
67 lapd = msgb_push(msg, LAPD_HDR_LEN);
68
69 len = msg->len - 2;
70
71 lapd[0] = (len >> 8) & 0xff;
72 lapd[1] = len & 0xff; /* length of bytes startign at lapd[2] */
73 lapd[2] = 0x00;
74 lapd[3] = 0x07;
75 lapd[4] = 0x01;
76 lapd[5] = 0x3e;
77 lapd[6] = 0x00;
78 lapd[7] = 0x00;
79 lapd[8] = msg->len - 10; /* length of bytes starting at lapd[10] */
80 lapd[9] = lapd[8] ^ 0x38;
81
82 msgb_enqueue(&sh->tx_queue, msg);
83 sh->fd.when |= BSC_FD_WRITE;
84
Harald Weltef80b7d32009-02-19 03:11:13 +000085 /* we try to immediately send */
86 handle_ser_write(&sh->fd);
87
Harald Weltec12d52b2009-02-01 21:39:06 +000088 return 0;
89}
90
91/* select.c callback in case we can write to the RS232 */
92static int handle_ser_write(struct bsc_fd *bfd)
93{
94 struct serial_handle *sh = bfd->data;
95 struct msgb *msg;
96 int written;
97
98 msg = msgb_dequeue(&sh->tx_queue);
99 if (!msg) {
100 bfd->when &= ~BSC_FD_WRITE;
101 return 0;
102 }
103
Harald Weltec50ea842009-04-29 22:32:10 +0000104 DEBUGP(DMI, "RS232 TX: %s\n", hexdump(msg->data, msg->len));
Harald Weltec12d52b2009-02-01 21:39:06 +0000105
106 /* send over serial line */
107 written = write(bfd->fd, msg->data, msg->len);
108 if (written < msg->len) {
109 perror("short write:");
110 msgb_free(msg);
111 return -1;
112 }
113
114 msgb_free(msg);
115 usleep(sh->delay_ms*1000);
116
117 return 0;
118}
119
120#define SERIAL_ALLOC_SIZE 300
121
122/* select.c callback in case we can read from the RS232 */
123static int handle_ser_read(struct bsc_fd *bfd)
124{
125 struct serial_handle *sh = bfd->data;
126 struct msgb *msg;
127 int rc = 0;
128
129 if (!sh->rx_msg) {
Harald Welte966636f2009-06-26 19:39:35 +0200130 sh->rx_msg = msgb_alloc(SERIAL_ALLOC_SIZE, "RS232 Rx");
Harald Weltec12d52b2009-02-01 21:39:06 +0000131 sh->rx_msg->l2h = NULL;
Harald Welte273feca2009-03-28 16:53:25 +0000132 sh->rx_msg->trx = sh->bts->c0;
Harald Weltec12d52b2009-02-01 21:39:06 +0000133 }
134 msg = sh->rx_msg;
135
136 /* first read two byes to obtain length */
137 if (msg->len < 2) {
138 rc = read(sh->fd.fd, msg->tail, 2 - msg->len);
139 if (rc < 0) {
140 perror("ERROR reading from serial port");
141 msgb_free(msg);
142 return rc;
143 }
144 msgb_put(msg, rc);
145
146 if (msg->len >= 2) {
147 /* parse LAPD payload length */
148 if (msg->data[0] != 0)
149 fprintf(stderr, "Suspicious header byte 0: 0x%02x\n",
150 msg->data[0]);
151
152 sh->rxmsg_bytes_missing = msg->data[0] << 8;
153 sh->rxmsg_bytes_missing += msg->data[1];
154
155 if (sh->rxmsg_bytes_missing < LAPD_HDR_LEN -2)
156 fprintf(stderr, "Invalid length in hdr: %u\n",
157 sh->rxmsg_bytes_missing);
158 }
159 } else {
160 /* try to read as many of the missing bytes as are available */
161 rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing);
162 if (rc < 0) {
163 perror("ERROR reading from serial port");
164 msgb_free(msg);
165 return rc;
166 }
167 msgb_put(msg, rc);
168 sh->rxmsg_bytes_missing -= rc;
169
170 if (sh->rxmsg_bytes_missing == 0) {
171 /* we have one complete message now */
172 sh->rx_msg = NULL;
173
174 if (msg->len > LAPD_HDR_LEN)
175 msg->l2h = msg->data + LAPD_HDR_LEN;
176
Harald Welte3cc4bf52009-02-28 13:08:01 +0000177 DEBUGP(DMI, "RS232 RX: %s\n", hexdump(msg->data, msg->len));
Harald Weltec12d52b2009-02-01 21:39:06 +0000178 rc = handle_serial_msg(msg);
179 }
180 }
181
182 return rc;
183}
184
185/* select.c callback */
186static int serial_fd_cb(struct bsc_fd *bfd, unsigned int what)
187{
188 int rc = 0;
189
190 if (what & BSC_FD_READ)
191 rc = handle_ser_read(bfd);
192
193 if (rc < 0)
194 return rc;
195
196 if (what & BSC_FD_WRITE)
197 rc = handle_ser_write(bfd);
198
199 return rc;
200}
201
Harald Welte273feca2009-03-28 16:53:25 +0000202int rs232_setup(const char *serial_port, unsigned int delay_ms,
203 struct gsm_bts *bts)
Harald Weltec12d52b2009-02-01 21:39:06 +0000204{
205 int rc, serial_fd;
206 struct termios tio;
207
208 serial_fd = open(serial_port, O_RDWR);
209 if (serial_fd < 0) {
210 perror("cannot open serial port:");
211 return serial_fd;
212 }
213
214 /* set baudrate */
215 rc = tcgetattr(serial_fd, &tio);
216 if (rc < 0) {
217 perror("tcgetattr()");
218 return rc;
219 }
220 cfsetispeed(&tio, B19200);
221 cfsetospeed(&tio, B19200);
222 tio.c_cflag |= (CREAD | CLOCAL | CS8);
223 tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
224 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
225 tio.c_iflag |= (INPCK | ISTRIP);
226 tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR);
227 tio.c_oflag &= ~(OPOST);
228 rc = tcsetattr(serial_fd, TCSADRAIN, &tio);
229 if (rc < 0) {
230 perror("tcsetattr()");
231 return rc;
232 }
233
234 INIT_LLIST_HEAD(&ser_handle->tx_queue);
235 ser_handle->fd.fd = serial_fd;
236 ser_handle->fd.when = BSC_FD_READ;
237 ser_handle->fd.cb = serial_fd_cb;
238 ser_handle->fd.data = ser_handle;
239 ser_handle->delay_ms = delay_ms;
Harald Welte273feca2009-03-28 16:53:25 +0000240 ser_handle->bts = bts;
Harald Weltec12d52b2009-02-01 21:39:06 +0000241 rc = bsc_register_fd(&ser_handle->fd);
242 if (rc < 0) {
243 fprintf(stderr, "could not register FD: %s\n",
244 strerror(rc));
245 return rc;
246 }
247
248 return 0;
249}