From c12d52bae4fbdda8bdc609323bb1ef91b07aced6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 1 Feb 2009 21:39:06 +0000 Subject: * improve parsing of status/phase response from BTS * split rs232 support into separate file (like misdn.c) --- include/openbsc/abis_nm.h | 12 ++- src/Makefile.am | 2 +- src/bs11_config.c | 208 ++------------------------------------- src/rs232.c | 245 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 261 insertions(+), 206 deletions(-) create mode 100644 src/rs232.c diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h index 8d8f7cca8..b8523b254 100644 --- a/include/openbsc/abis_nm.h +++ b/include/openbsc/abis_nm.h @@ -407,7 +407,10 @@ enum abis_bs11_phase { BS11_STATE_SOFTWARE_RQD = 0x01, BS11_STATE_LOAD_SMU_INTENDED = 0x11, BS11_STATE_LOAD_SMU_SAFETY = 0x21, + BS11_STATE_LOAD_FAILED = 0x31, + BS11_STATE_LOAD_DIAGNOSTIC = 0x41, BS11_STATE_WARM_UP = 0x51, + BS11_STATE_WARM_UP_2 = 0x52, BS11_STATE_WAIT_MIN_CFG = 0x62, BS11_STATE_MAINTENANCE = 0x72, BS11_STATE_LOAD_MBCCU = 0x92, @@ -415,14 +418,15 @@ enum abis_bs11_phase { BS11_STATE_NORMAL = 0x03, }; +/* FIXME: this is not correct, please parse this correctly */ struct abis_nm_bs11_state { - u_int8_t unknown; - u_int8_t unknown2; + u_int8_t tag_f0; + u_int8_t len_f0; u_int8_t phase; u_int8_t mbccu; - u_int8_t unknown3; u_int8_t ccu; - u_int8_t t_link; + u_int8_t tag_f1; + u_int8_t len_f1; u_int8_t abis_link; } __attribute__((packed)); diff --git a/src/Makefile.am b/src/Makefile.am index e4c754478..53b290371 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,4 +9,4 @@ bsc_hack_SOURCES = bsc_hack.c misdn.c abis_rsl.c abis_nm.c gsm_04_08.c gsm_data. trau_frame.c paging.c bsc_hack_LDADD = -ldl -ldbi -bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c select.c timer.c +bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c select.c timer.c rs232.c diff --git a/src/bs11_config.c b/src/bs11_config.c index af73d23ae..e2916ab06 100644 --- a/src/bs11_config.c +++ b/src/bs11_config.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -68,18 +67,8 @@ static const char *trx1_password = "1111111111"; static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 }; -struct serial_handle { - struct bsc_fd fd; - struct llist_head tx_queue; - struct msgb *rx_msg; - unsigned int rxmsg_bytes_missing; -}; - -/* FIXME: this needs to go */ -static struct serial_handle _ser_handle, *ser_handle = &_ser_handle; - -static int handle_serial_msg(struct msgb *rx_msg); +int handle_serial_msg(struct msgb *rx_msg); static int create_trx1_objects(struct gsm_bts *bts) { @@ -133,158 +122,10 @@ static char *serial_port = "/dev/ttyUSB0"; static char *fname_safety = "BTSBMC76.SWI"; static char *fname_software = "HS011106.SWL"; static int delay_ms = 0; -static int serial_fd = -1; static int have_trx1 = 0; static int win_size = 8; static struct gsm_bts *g_bts; -/* adaption layer from GSM 08.59 + 12.21 to RS232 */ - -#define LAPD_HDR_LEN 10 - -/* callback from abis_nm */ -int _abis_nm_sendmsg(struct msgb *msg) -{ - struct serial_handle *sh = ser_handle; - u_int8_t *lapd; - unsigned int len; - - msg->l2h = msg->data; - - /* prepend LAPD header */ - lapd = msgb_push(msg, LAPD_HDR_LEN); - - len = msg->len - 2; - - lapd[0] = (len >> 8) & 0xff; - lapd[1] = len & 0xff; /* length of bytes startign at lapd[2] */ - lapd[2] = 0x00; - lapd[3] = 0x07; - lapd[4] = 0x01; - lapd[5] = 0x3e; - lapd[6] = 0x00; - lapd[7] = 0x00; - lapd[8] = msg->len - 10; /* length of bytes starting at lapd[10] */ - lapd[9] = lapd[8] ^ 0x38; - - msgb_enqueue(&sh->tx_queue, msg); - sh->fd.when |= BSC_FD_WRITE; - - return 0; -} - -/* select.c callback in case we can write to the RS232 */ -static int handle_ser_write(struct bsc_fd *bfd) -{ - struct serial_handle *sh = bfd->data; - struct msgb *msg; - int written; - - msg = msgb_dequeue(&sh->tx_queue); - if (!msg) { - bfd->when &= ~BSC_FD_WRITE; - return 0; - } - - fprintf(stdout, "TX: "); - hexdump(msg->data, msg->len); - - /* send over serial line */ - written = write(serial_fd, msg->data, msg->len); - if (written < msg->len) { - perror("short write:"); - msgb_free(msg); - return -1; - } - - msgb_free(msg); - usleep(delay_ms*1000); - - return 0; -} - -#define SERIAL_ALLOC_SIZE 300 - -/* select.c callback in case we can read from the RS232 */ -static int handle_ser_read(struct bsc_fd *bfd) -{ - struct serial_handle *sh = bfd->data; - struct msgb *msg; - int rc = 0; - - if (!sh->rx_msg) { - sh->rx_msg = msgb_alloc(SERIAL_ALLOC_SIZE); - sh->rx_msg->l2h = NULL; - } - msg = sh->rx_msg; - - /* first read two byes to obtain length */ - if (msg->len < 2) { - rc = read(sh->fd.fd, msg->tail, 2 - msg->len); - if (rc < 0) { - perror("ERROR reading from serial port"); - msgb_free(msg); - return rc; - } - msgb_put(msg, rc); - - if (msg->len >= 2) { - /* parse LAPD payload length */ - if (msg->data[0] != 0) - fprintf(stderr, "Suspicious header byte 0: 0x%02x\n", - msg->data[0]); - - sh->rxmsg_bytes_missing = msg->data[0] << 8; - sh->rxmsg_bytes_missing += msg->data[1]; - - if (sh->rxmsg_bytes_missing < LAPD_HDR_LEN -2) - fprintf(stderr, "Invalid length in hdr: %u\n", - sh->rxmsg_bytes_missing); - } - } else { - /* try to read as many of the missing bytes as are available */ - rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing); - if (rc < 0) { - perror("ERROR reading from serial port"); - msgb_free(msg); - return rc; - } - msgb_put(msg, rc); - sh->rxmsg_bytes_missing -= rc; - - if (sh->rxmsg_bytes_missing == 0) { - /* we have one complete message now */ - sh->rx_msg = NULL; - - if (msg->len > LAPD_HDR_LEN) - msg->l2h = msg->data + LAPD_HDR_LEN; - - fprintf(stdout, "RX: "); - hexdump(msg->data, msg->len); - rc = handle_serial_msg(msg); - } - } - - return rc; -} - -/* select.c callback */ -static int serial_fd_cb(struct bsc_fd *bfd, unsigned int what) -{ - int rc = 0; - - if (what & BSC_FD_READ) - rc = handle_ser_read(bfd); - - if (rc < 0) - return rc; - - if (what & BSC_FD_WRITE) - rc = handle_ser_write(bfd); - - return rc; -} - static int file_is_readable(const char *fname) { int rc; @@ -374,12 +215,13 @@ static void print_state(struct abis_nm_bs11_state *st) enum abis_bs11_phase phase = st->phase; printf("T-Link: %-9s Abis-link: %-9s MBCCU0: %-11s MBCCU1: %-11s PHASE: %u SUBPHASE: ", - linkstate_name(st->t_link), linkstate_name(st->abis_link), + linkstate_name(st->abis_link >> 4), linkstate_name(st->abis_link & 0xf), mbccu_load_name(st->mbccu >> 4), mbccu_load_name(st->mbccu & 0xf), phase & 0xf); switch (phase) { case BS11_STATE_WARM_UP: + case BS11_STATE_WARM_UP_2: printf("Warm Up...\n"); break; case BS11_STATE_LOAD_SMU_SAFETY: @@ -469,13 +311,14 @@ static int handle_state_resp(enum abis_bs11_phase state) } /* handle a fully-received message/packet from the RS232 port */ -static int handle_serial_msg(struct msgb *rx_msg) +int handle_serial_msg(struct msgb *rx_msg) { struct abis_om_hdr *oh; struct abis_om_fom_hdr *foh; struct abis_nm_bs11_state *st; int rc = -1; +#if 0 if (rx_msg->len < LAPD_HDR_LEN + sizeof(struct abis_om_fom_hdr) + sizeof(struct abis_om_hdr)) { @@ -488,6 +331,7 @@ static int handle_serial_msg(struct msgb *rx_msg) } else fprintf(stderr, "unknown BS11 message\n"); } +#endif oh = (struct abis_om_hdr *) msgb_l2(rx_msg); foh = (struct abis_om_fom_hdr *) oh->data; @@ -612,37 +456,10 @@ static void signal_handler(int signal) int main(int argc, char **argv) { struct gsm_network *gsmnet; - struct termios tio; int rc; handle_options(argc, argv); - serial_fd = open(serial_port, O_RDWR); - if (serial_fd < 0) { - perror("cannot open serial port:"); - exit(1); - } - - /* set baudrate */ - rc = tcgetattr(serial_fd, &tio); - if (rc < 0) { - perror("tcgetattr()"); - exit(1); - } - cfsetispeed(&tio, B19200); - cfsetospeed(&tio, B19200); - tio.c_cflag |= (CREAD | CLOCAL | CS8); - tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); - tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - tio.c_iflag |= (INPCK | ISTRIP); - tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR); - tio.c_oflag &= ~(OPOST); - rc = tcsetattr(serial_fd, TCSADRAIN, &tio); - if (rc < 0) { - perror("tcsetattr()"); - exit(1); - } - gsmnet = gsm_network_init(1, 1, 1); if (!gsmnet) { fprintf(stderr, "Unable to allocate gsm network\n"); @@ -650,17 +467,7 @@ int main(int argc, char **argv) } g_bts = &gsmnet->bts[0]; - INIT_LLIST_HEAD(&ser_handle->tx_queue); - ser_handle->fd.fd = serial_fd; - ser_handle->fd.when = BSC_FD_READ; - ser_handle->fd.cb = serial_fd_cb; - ser_handle->fd.data = ser_handle; - rc = bsc_register_fd(&ser_handle->fd); - if (rc < 0) { - fprintf(stderr, "could not register FD: %s\n", - strerror(rc)); - exit(1); - } + rs232_setup(serial_port, delay_ms); signal(SIGINT, &signal_handler); @@ -673,6 +480,5 @@ int main(int argc, char **argv) abis_nm_bs11_factory_logon(g_bts, 0); - close(serial_fd); exit(0); } diff --git a/src/rs232.c b/src/rs232.c new file mode 100644 index 000000000..90e881830 --- /dev/null +++ b/src/rs232.c @@ -0,0 +1,245 @@ +/* OpenBSC BS-11 T-Link interface using POSIX serial port */ + +/* (C) 2008-2009 by Harald Welte + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* adaption layer from GSM 08.59 + 12.21 to RS232 */ + +struct serial_handle { + struct bsc_fd fd; + struct llist_head tx_queue; + + struct msgb *rx_msg; + unsigned int rxmsg_bytes_missing; + + unsigned int delay_ms; +}; + +/* FIXME: this needs to go */ +static struct serial_handle _ser_handle, *ser_handle = &_ser_handle; + +#define LAPD_HDR_LEN 10 + +/* callback from abis_nm */ +int _abis_nm_sendmsg(struct msgb *msg) +{ + struct serial_handle *sh = ser_handle; + u_int8_t *lapd; + unsigned int len; + + msg->l2h = msg->data; + + /* prepend LAPD header */ + lapd = msgb_push(msg, LAPD_HDR_LEN); + + len = msg->len - 2; + + lapd[0] = (len >> 8) & 0xff; + lapd[1] = len & 0xff; /* length of bytes startign at lapd[2] */ + lapd[2] = 0x00; + lapd[3] = 0x07; + lapd[4] = 0x01; + lapd[5] = 0x3e; + lapd[6] = 0x00; + lapd[7] = 0x00; + lapd[8] = msg->len - 10; /* length of bytes starting at lapd[10] */ + lapd[9] = lapd[8] ^ 0x38; + + msgb_enqueue(&sh->tx_queue, msg); + sh->fd.when |= BSC_FD_WRITE; + + return 0; +} + +/* select.c callback in case we can write to the RS232 */ +static int handle_ser_write(struct bsc_fd *bfd) +{ + struct serial_handle *sh = bfd->data; + struct msgb *msg; + int written; + + msg = msgb_dequeue(&sh->tx_queue); + if (!msg) { + bfd->when &= ~BSC_FD_WRITE; + return 0; + } + + if (debug_mask & DMI) { + fprintf(stdout, "RS232 TX: "); + hexdump(msg->data, msg->len); + } + + /* send over serial line */ + written = write(bfd->fd, msg->data, msg->len); + if (written < msg->len) { + perror("short write:"); + msgb_free(msg); + return -1; + } + + msgb_free(msg); + usleep(sh->delay_ms*1000); + + return 0; +} + +#define SERIAL_ALLOC_SIZE 300 + +/* select.c callback in case we can read from the RS232 */ +static int handle_ser_read(struct bsc_fd *bfd) +{ + struct serial_handle *sh = bfd->data; + struct msgb *msg; + int rc = 0; + + if (!sh->rx_msg) { + sh->rx_msg = msgb_alloc(SERIAL_ALLOC_SIZE); + sh->rx_msg->l2h = NULL; + } + msg = sh->rx_msg; + + /* first read two byes to obtain length */ + if (msg->len < 2) { + rc = read(sh->fd.fd, msg->tail, 2 - msg->len); + if (rc < 0) { + perror("ERROR reading from serial port"); + msgb_free(msg); + return rc; + } + msgb_put(msg, rc); + + if (msg->len >= 2) { + /* parse LAPD payload length */ + if (msg->data[0] != 0) + fprintf(stderr, "Suspicious header byte 0: 0x%02x\n", + msg->data[0]); + + sh->rxmsg_bytes_missing = msg->data[0] << 8; + sh->rxmsg_bytes_missing += msg->data[1]; + + if (sh->rxmsg_bytes_missing < LAPD_HDR_LEN -2) + fprintf(stderr, "Invalid length in hdr: %u\n", + sh->rxmsg_bytes_missing); + } + } else { + /* try to read as many of the missing bytes as are available */ + rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing); + if (rc < 0) { + perror("ERROR reading from serial port"); + msgb_free(msg); + return rc; + } + msgb_put(msg, rc); + sh->rxmsg_bytes_missing -= rc; + + if (sh->rxmsg_bytes_missing == 0) { + /* we have one complete message now */ + sh->rx_msg = NULL; + + if (msg->len > LAPD_HDR_LEN) + msg->l2h = msg->data + LAPD_HDR_LEN; + + if (debug_mask & DMI) { + fprintf(stdout, "RS232 RX: "); + hexdump(msg->data, msg->len); + } + rc = handle_serial_msg(msg); + } + } + + return rc; +} + +/* select.c callback */ +static int serial_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + int rc = 0; + + if (what & BSC_FD_READ) + rc = handle_ser_read(bfd); + + if (rc < 0) + return rc; + + if (what & BSC_FD_WRITE) + rc = handle_ser_write(bfd); + + return rc; +} + +int rs232_setup(const char *serial_port, unsigned int delay_ms) +{ + int rc, serial_fd; + struct termios tio; + + serial_fd = open(serial_port, O_RDWR); + if (serial_fd < 0) { + perror("cannot open serial port:"); + return serial_fd; + } + + /* set baudrate */ + rc = tcgetattr(serial_fd, &tio); + if (rc < 0) { + perror("tcgetattr()"); + return rc; + } + cfsetispeed(&tio, B19200); + cfsetospeed(&tio, B19200); + tio.c_cflag |= (CREAD | CLOCAL | CS8); + tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); + tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + tio.c_iflag |= (INPCK | ISTRIP); + tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR); + tio.c_oflag &= ~(OPOST); + rc = tcsetattr(serial_fd, TCSADRAIN, &tio); + if (rc < 0) { + perror("tcsetattr()"); + return rc; + } + + INIT_LLIST_HEAD(&ser_handle->tx_queue); + ser_handle->fd.fd = serial_fd; + ser_handle->fd.when = BSC_FD_READ; + ser_handle->fd.cb = serial_fd_cb; + ser_handle->fd.data = ser_handle; + ser_handle->delay_ms = delay_ms; + rc = bsc_register_fd(&ser_handle->fd); + if (rc < 0) { + fprintf(stderr, "could not register FD: %s\n", + strerror(rc)); + return rc; + } + + return 0; +} -- cgit v1.2.3